mirror of
https://github.com/TeaOSLab/EdgeAPI.git
synced 2025-11-03 06:40:26 +08:00
SSH认证支持sudo
This commit is contained in:
@@ -73,7 +73,7 @@ func (this *NodeGrantDAO) FindNodeGrantName(tx *dbs.Tx, id uint32) (string, erro
|
||||
}
|
||||
|
||||
// CreateGrant 创建认证信息
|
||||
func (this *NodeGrantDAO) CreateGrant(tx *dbs.Tx, adminId int64, name string, method string, username string, password string, privateKey string, passphrase string, description string, nodeId int64) (grantId int64, err error) {
|
||||
func (this *NodeGrantDAO) CreateGrant(tx *dbs.Tx, adminId int64, name string, method string, username string, password string, privateKey string, passphrase string, description string, nodeId int64, su bool) (grantId int64, err error) {
|
||||
op := NewNodeGrantOperator()
|
||||
op.AdminId = adminId
|
||||
op.Name = name
|
||||
@@ -83,12 +83,12 @@ func (this *NodeGrantDAO) CreateGrant(tx *dbs.Tx, adminId int64, name string, me
|
||||
case "user":
|
||||
op.Username = username
|
||||
op.Password = password
|
||||
op.Su = false // TODO 需要做到前端可以配置
|
||||
case "privateKey":
|
||||
op.Username = username
|
||||
op.PrivateKey = privateKey
|
||||
op.Passphrase = passphrase
|
||||
}
|
||||
op.Su = su
|
||||
op.Description = description
|
||||
op.NodeId = nodeId
|
||||
op.State = NodeGrantStateEnabled
|
||||
@@ -97,7 +97,7 @@ func (this *NodeGrantDAO) CreateGrant(tx *dbs.Tx, adminId int64, name string, me
|
||||
}
|
||||
|
||||
// UpdateGrant 修改认证信息
|
||||
func (this *NodeGrantDAO) UpdateGrant(tx *dbs.Tx, grantId int64, name string, method string, username string, password string, privateKey string, passphrase string, description string, nodeId int64) error {
|
||||
func (this *NodeGrantDAO) UpdateGrant(tx *dbs.Tx, grantId int64, name string, method string, username string, password string, privateKey string, passphrase string, description string, nodeId int64, su bool) error {
|
||||
if grantId <= 0 {
|
||||
return errors.New("invalid grantId")
|
||||
}
|
||||
@@ -111,12 +111,12 @@ func (this *NodeGrantDAO) UpdateGrant(tx *dbs.Tx, grantId int64, name string, me
|
||||
case "user":
|
||||
op.Username = username
|
||||
op.Password = password
|
||||
op.Su = false // TODO 需要做到前端可以配置
|
||||
case "privateKey":
|
||||
op.Username = username
|
||||
op.PrivateKey = privateKey
|
||||
op.Passphrase = passphrase
|
||||
}
|
||||
op.Su = su
|
||||
op.Description = description
|
||||
op.NodeId = nodeId
|
||||
err := this.Save(tx, op)
|
||||
|
||||
@@ -8,4 +8,5 @@ type Credentials struct {
|
||||
PrivateKey string
|
||||
Passphrase string
|
||||
Method string
|
||||
Sudo bool
|
||||
}
|
||||
|
||||
@@ -94,7 +94,13 @@ func (this *BaseInstaller) Login(credentials *Credentials) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if credentials.Sudo {
|
||||
client.Sudo(credentials.Password)
|
||||
}
|
||||
|
||||
this.client = client
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -146,6 +152,10 @@ func (this *BaseInstaller) InstallHelper(targetDir string, role nodeconfigs.Node
|
||||
return env, err
|
||||
}
|
||||
|
||||
if len(uname) == 0 {
|
||||
return nil, errors.New("unable to execute 'uname -a' on this system")
|
||||
}
|
||||
|
||||
osName := ""
|
||||
archName := ""
|
||||
if strings.Contains(uname, "Darwin") {
|
||||
|
||||
@@ -97,6 +97,12 @@ func (this *NodeInstaller) Install(dir string, params interface{}, installStatus
|
||||
// 修改配置文件
|
||||
{
|
||||
configFile := dir + "/edge-node/configs/api.yaml"
|
||||
|
||||
// sudo之后我们需要修改配置目录才能写入文件
|
||||
if this.client.sudo {
|
||||
_, _, _ = this.client.Exec("chown " + this.client.User() + " " + filepath.Dir(configFile))
|
||||
}
|
||||
|
||||
var data = []byte(`rpc:
|
||||
endpoints: [ ${endpoints} ]
|
||||
nodeId: "${nodeId}"
|
||||
@@ -108,7 +114,7 @@ secret: "${nodeSecret}"`)
|
||||
|
||||
_, err = this.client.WriteFile(configFile, data)
|
||||
if err != nil {
|
||||
return errors.New("write 'configs/api.yaml': " + err.Error())
|
||||
return errors.New("write '" + configFile + "': " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -97,6 +97,12 @@ func (this *NSNodeInstaller) Install(dir string, params interface{}, installStat
|
||||
// 修改配置文件
|
||||
{
|
||||
configFile := dir + "/edge-dns/configs/api.yaml"
|
||||
|
||||
// sudo之后我们需要修改配置目录才能写入文件
|
||||
if this.client.sudo {
|
||||
_, _, _ = this.client.Exec("chown " + this.client.User() + " " + filepath.Dir(configFile))
|
||||
}
|
||||
|
||||
var data = []byte(`rpc:
|
||||
endpoints: [ ${endpoints} ]
|
||||
nodeId: "${nodeId}"
|
||||
@@ -108,7 +114,7 @@ secret: "${nodeSecret}"`)
|
||||
|
||||
_, err = this.client.WriteFile(configFile, data)
|
||||
if err != nil {
|
||||
return errors.New("write 'configs/api.yaml': " + err.Error())
|
||||
return errors.New("write '" + configFile + "': " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -133,24 +133,6 @@ func (this *NodeQueue) InstallNode(nodeId int64, installStatus *models.NodeInsta
|
||||
return errors.New("can not find user grant with id '" + numberutils.FormatInt64(loginParams.GrantId) + "'")
|
||||
}
|
||||
|
||||
// 安装目录
|
||||
installDir := node.InstallDir
|
||||
if len(installDir) == 0 {
|
||||
clusterId := node.ClusterId
|
||||
cluster, err := models.SharedNodeClusterDAO.FindEnabledNodeCluster(nil, int64(clusterId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cluster == nil {
|
||||
return errors.New("can not find cluster, ID:'" + fmt.Sprintf("%d", clusterId) + "'")
|
||||
}
|
||||
installDir = cluster.InstallDir
|
||||
if len(installDir) == 0 {
|
||||
// 默认是 $登录用户/edge-node
|
||||
installDir = "/" + grant.Username + "/edge-node"
|
||||
}
|
||||
}
|
||||
|
||||
// API终端
|
||||
apiNodes, err := models.SharedAPINodeDAO.FindAllEnabledAndOnAPINodes(nil)
|
||||
if err != nil {
|
||||
@@ -187,6 +169,7 @@ func (this *NodeQueue) InstallNode(nodeId int64, installStatus *models.NodeInsta
|
||||
PrivateKey: grant.PrivateKey,
|
||||
Passphrase: grant.Passphrase,
|
||||
Method: grant.Method,
|
||||
Sudo: grant.Su == 1,
|
||||
})
|
||||
if err != nil {
|
||||
installStatus.ErrorCode = "SSH_LOGIN_FAILED"
|
||||
@@ -196,6 +179,24 @@ func (this *NodeQueue) InstallNode(nodeId int64, installStatus *models.NodeInsta
|
||||
_ = installer.Close()
|
||||
}()
|
||||
|
||||
// 安装目录
|
||||
installDir := node.InstallDir
|
||||
if len(installDir) == 0 {
|
||||
clusterId := node.ClusterId
|
||||
cluster, err := models.SharedNodeClusterDAO.FindEnabledNodeCluster(nil, int64(clusterId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cluster == nil {
|
||||
return errors.New("can not find cluster, ID:'" + fmt.Sprintf("%d", clusterId) + "'")
|
||||
}
|
||||
installDir = cluster.InstallDir
|
||||
if len(installDir) == 0 {
|
||||
// 默认是 $登录用户/edge-node
|
||||
installDir = installer.client.UserHome() + "/edge-node"
|
||||
}
|
||||
}
|
||||
|
||||
err = installer.Install(installDir, params, installStatus)
|
||||
return err
|
||||
}
|
||||
@@ -250,24 +251,6 @@ func (this *NodeQueue) StartNode(nodeId int64) error {
|
||||
return errors.New("can not find user grant with id '" + numberutils.FormatInt64(loginParams.GrantId) + "'")
|
||||
}
|
||||
|
||||
// 安装目录
|
||||
installDir := node.InstallDir
|
||||
if len(installDir) == 0 {
|
||||
clusterId := node.ClusterId
|
||||
cluster, err := models.SharedNodeClusterDAO.FindEnabledNodeCluster(nil, int64(clusterId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cluster == nil {
|
||||
return errors.New("can not find cluster, ID:'" + fmt.Sprintf("%d", clusterId) + "'")
|
||||
}
|
||||
installDir = cluster.InstallDir
|
||||
if len(installDir) == 0 {
|
||||
// 默认是 $登录用户/edge-node
|
||||
installDir = "/" + grant.Username + "/edge-node"
|
||||
}
|
||||
}
|
||||
|
||||
installer := &NodeInstaller{}
|
||||
err = installer.Login(&Credentials{
|
||||
Host: loginParams.Host,
|
||||
@@ -277,6 +260,7 @@ func (this *NodeQueue) StartNode(nodeId int64) error {
|
||||
PrivateKey: grant.PrivateKey,
|
||||
Passphrase: grant.Passphrase,
|
||||
Method: grant.Method,
|
||||
Sudo: grant.Su == 1,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -286,16 +270,16 @@ func (this *NodeQueue) StartNode(nodeId int64) error {
|
||||
}()
|
||||
|
||||
// 检查命令是否存在
|
||||
exeFile := installDir + "/edge-node/bin/edge-node"
|
||||
_, err = installer.client.Stat(exeFile)
|
||||
exe, err := this.lookupNodeExe(node, installer.client)
|
||||
if err != nil {
|
||||
return errors.New("edge node is not installed correctly, can not find executable file: " + exeFile)
|
||||
return errors.New("edge node was not installed correctly, can not find executable file")
|
||||
}
|
||||
|
||||
// 我们先尝试Systemd启动
|
||||
_, _, _ = installer.client.Exec("systemctl start edge-node")
|
||||
|
||||
_, stderr, err := installer.client.Exec(exeFile + " start")
|
||||
// 执行start
|
||||
_, stderr, err := installer.client.Exec("sudo " + exe + " start")
|
||||
if err != nil {
|
||||
return errors.New("start failed: " + err.Error())
|
||||
}
|
||||
@@ -356,24 +340,6 @@ func (this *NodeQueue) StopNode(nodeId int64) error {
|
||||
return errors.New("can not find user grant with id '" + numberutils.FormatInt64(loginParams.GrantId) + "'")
|
||||
}
|
||||
|
||||
// 安装目录
|
||||
installDir := node.InstallDir
|
||||
if len(installDir) == 0 {
|
||||
clusterId := node.ClusterId
|
||||
cluster, err := models.SharedNodeClusterDAO.FindEnabledNodeCluster(nil, int64(clusterId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cluster == nil {
|
||||
return errors.New("can not find cluster, ID:'" + fmt.Sprintf("%d", clusterId) + "'")
|
||||
}
|
||||
installDir = cluster.InstallDir
|
||||
if len(installDir) == 0 {
|
||||
// 默认是 $登录用户/edge-node
|
||||
installDir = "/" + grant.Username + "/edge-node"
|
||||
}
|
||||
}
|
||||
|
||||
installer := &NodeInstaller{}
|
||||
err = installer.Login(&Credentials{
|
||||
Host: loginParams.Host,
|
||||
@@ -383,6 +349,7 @@ func (this *NodeQueue) StopNode(nodeId int64) error {
|
||||
PrivateKey: grant.PrivateKey,
|
||||
Passphrase: grant.Passphrase,
|
||||
Method: grant.Method,
|
||||
Sudo: grant.Su == 1,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -392,16 +359,16 @@ func (this *NodeQueue) StopNode(nodeId int64) error {
|
||||
}()
|
||||
|
||||
// 检查命令是否存在
|
||||
exeFile := installDir + "/edge-node/bin/edge-node"
|
||||
_, err = installer.client.Stat(exeFile)
|
||||
exe, err := this.lookupNodeExe(node, installer.client)
|
||||
if err != nil {
|
||||
return errors.New("edge node is not installed correctly, can not find executable file: " + exeFile)
|
||||
return errors.New("edge node was not installed correctly, can not find executable file")
|
||||
}
|
||||
|
||||
// 我们先尝试Systemd停止
|
||||
_, _, _ = installer.client.Exec("systemctl stop edge-node")
|
||||
|
||||
_, stderr, err := installer.client.Exec(exeFile + " stop")
|
||||
// 执行stop
|
||||
_, stderr, err := installer.client.Exec(exe + " stop")
|
||||
if err != nil {
|
||||
return errors.New("stop failed: " + err.Error())
|
||||
}
|
||||
@@ -411,3 +378,38 @@ func (this *NodeQueue) StopNode(nodeId int64) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *NodeQueue) lookupNodeExe(node *models.Node, client *SSHClient) (string, error) {
|
||||
// 安装目录
|
||||
var nodeDirs = []string{}
|
||||
if len(node.InstallDir) > 0 {
|
||||
nodeDirs = append(nodeDirs, node.InstallDir)
|
||||
}
|
||||
clusterId := node.ClusterId
|
||||
cluster, err := models.SharedNodeClusterDAO.FindEnabledNodeCluster(nil, int64(clusterId))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if cluster == nil {
|
||||
return "", errors.New("can not find cluster, ID:'" + fmt.Sprintf("%d", clusterId) + "'")
|
||||
}
|
||||
if len(cluster.InstallDir) > 0 {
|
||||
nodeDirs = append(nodeDirs, cluster.InstallDir)
|
||||
}
|
||||
|
||||
// 默认是 $登录用户/edge-node
|
||||
nodeDirs = append(nodeDirs, client.UserHome()+"/edge-node")
|
||||
|
||||
// edge-boot安装目录
|
||||
nodeDirs = append(nodeDirs, "/usr/local/goedge")
|
||||
|
||||
for _, dir := range nodeDirs {
|
||||
var path = dir + "/edge-node/bin/edge-node"
|
||||
_, err := client.sftp.Stat(path)
|
||||
if err == nil {
|
||||
return path, nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", nil
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
)
|
||||
|
||||
func TestQueue_InstallNode(t *testing.T) {
|
||||
queue := NewQueue()
|
||||
queue := NewNodeQueue()
|
||||
err := queue.InstallNodeProcess(16, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -133,24 +133,6 @@ func (this *NSNodeQueue) InstallNode(nodeId int64, installStatus *models.NodeIns
|
||||
return errors.New("can not find user grant with id '" + numberutils.FormatInt64(loginParams.GrantId) + "'")
|
||||
}
|
||||
|
||||
// 安装目录
|
||||
installDir := node.InstallDir
|
||||
if len(installDir) == 0 {
|
||||
clusterId := node.ClusterId
|
||||
cluster, err := models.SharedNSClusterDAO.FindEnabledNSCluster(nil, int64(clusterId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cluster == nil {
|
||||
return errors.New("can not find cluster, ID:'" + fmt.Sprintf("%d", clusterId) + "'")
|
||||
}
|
||||
installDir = cluster.InstallDir
|
||||
if len(installDir) == 0 {
|
||||
// 默认是 $登录用户/edge-dns
|
||||
installDir = "/" + grant.Username + "/edge-dns"
|
||||
}
|
||||
}
|
||||
|
||||
// API终端
|
||||
apiNodes, err := models.SharedAPINodeDAO.FindAllEnabledAndOnAPINodes(nil)
|
||||
if err != nil {
|
||||
@@ -187,6 +169,7 @@ func (this *NSNodeQueue) InstallNode(nodeId int64, installStatus *models.NodeIns
|
||||
PrivateKey: grant.PrivateKey,
|
||||
Passphrase: grant.Passphrase,
|
||||
Method: grant.Method,
|
||||
Sudo: grant.Su == 1,
|
||||
})
|
||||
if err != nil {
|
||||
installStatus.ErrorCode = "SSH_LOGIN_FAILED"
|
||||
@@ -196,6 +179,24 @@ func (this *NSNodeQueue) InstallNode(nodeId int64, installStatus *models.NodeIns
|
||||
_ = installer.Close()
|
||||
}()
|
||||
|
||||
// 安装目录
|
||||
installDir := node.InstallDir
|
||||
if len(installDir) == 0 {
|
||||
clusterId := node.ClusterId
|
||||
cluster, err := models.SharedNSClusterDAO.FindEnabledNSCluster(nil, int64(clusterId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cluster == nil {
|
||||
return errors.New("can not find cluster, ID:'" + fmt.Sprintf("%d", clusterId) + "'")
|
||||
}
|
||||
installDir = cluster.InstallDir
|
||||
if len(installDir) == 0 {
|
||||
// 默认是 $登录用户/edge-dns
|
||||
installDir = installer.client.UserHome() + "/edge-dns"
|
||||
}
|
||||
}
|
||||
|
||||
err = installer.Install(installDir, params, installStatus)
|
||||
return err
|
||||
}
|
||||
@@ -250,6 +251,24 @@ func (this *NSNodeQueue) StartNode(nodeId int64) error {
|
||||
return errors.New("can not find user grant with id '" + numberutils.FormatInt64(loginParams.GrantId) + "'")
|
||||
}
|
||||
|
||||
installer := &NSNodeInstaller{}
|
||||
err = installer.Login(&Credentials{
|
||||
Host: loginParams.Host,
|
||||
Port: loginParams.Port,
|
||||
Username: grant.Username,
|
||||
Password: grant.Password,
|
||||
PrivateKey: grant.PrivateKey,
|
||||
Passphrase: grant.Passphrase,
|
||||
Method: grant.Method,
|
||||
Sudo: grant.Su == 1,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = installer.Close()
|
||||
}()
|
||||
|
||||
// 安装目录
|
||||
installDir := node.InstallDir
|
||||
if len(installDir) == 0 {
|
||||
@@ -264,27 +283,10 @@ func (this *NSNodeQueue) StartNode(nodeId int64) error {
|
||||
installDir = cluster.InstallDir
|
||||
if len(installDir) == 0 {
|
||||
// 默认是 $登录用户/edge-dns
|
||||
installDir = "/" + grant.Username + "/edge-dns"
|
||||
installDir = installer.client.UserHome() + "/edge-dns"
|
||||
}
|
||||
}
|
||||
|
||||
installer := &NSNodeInstaller{}
|
||||
err = installer.Login(&Credentials{
|
||||
Host: loginParams.Host,
|
||||
Port: loginParams.Port,
|
||||
Username: grant.Username,
|
||||
Password: grant.Password,
|
||||
PrivateKey: grant.PrivateKey,
|
||||
Passphrase: grant.Passphrase,
|
||||
Method: grant.Method,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = installer.Close()
|
||||
}()
|
||||
|
||||
// 检查命令是否存在
|
||||
exeFile := installDir + "/edge-dns/bin/edge-dns"
|
||||
_, err = installer.client.Stat(exeFile)
|
||||
@@ -356,6 +358,24 @@ func (this *NSNodeQueue) StopNode(nodeId int64) error {
|
||||
return errors.New("can not find user grant with id '" + numberutils.FormatInt64(loginParams.GrantId) + "'")
|
||||
}
|
||||
|
||||
installer := &NSNodeInstaller{}
|
||||
err = installer.Login(&Credentials{
|
||||
Host: loginParams.Host,
|
||||
Port: loginParams.Port,
|
||||
Username: grant.Username,
|
||||
Password: grant.Password,
|
||||
PrivateKey: grant.PrivateKey,
|
||||
Passphrase: grant.Passphrase,
|
||||
Method: grant.Method,
|
||||
Sudo: grant.Su == 1,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = installer.Close()
|
||||
}()
|
||||
|
||||
// 安装目录
|
||||
installDir := node.InstallDir
|
||||
if len(installDir) == 0 {
|
||||
@@ -370,27 +390,10 @@ func (this *NSNodeQueue) StopNode(nodeId int64) error {
|
||||
installDir = cluster.InstallDir
|
||||
if len(installDir) == 0 {
|
||||
// 默认是 $登录用户/edge-dns
|
||||
installDir = "/" + grant.Username + "/edge-dns"
|
||||
installDir = installer.client.UserHome() + "/edge-dns"
|
||||
}
|
||||
}
|
||||
|
||||
installer := &NSNodeInstaller{}
|
||||
err = installer.Login(&Credentials{
|
||||
Host: loginParams.Host,
|
||||
Port: loginParams.Port,
|
||||
Username: grant.Username,
|
||||
Password: grant.Password,
|
||||
PrivateKey: grant.PrivateKey,
|
||||
Passphrase: grant.Passphrase,
|
||||
Method: grant.Method,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = installer.Close()
|
||||
}()
|
||||
|
||||
// 检查命令是否存在
|
||||
exeFile := installDir + "/edge-dns/bin/edge-dns"
|
||||
_, err = installer.client.Stat(exeFile)
|
||||
|
||||
@@ -13,6 +13,9 @@ import (
|
||||
type SSHClient struct {
|
||||
raw *ssh.Client
|
||||
sftp *sftp.Client
|
||||
|
||||
sudo bool
|
||||
sudoPassword string
|
||||
}
|
||||
|
||||
func NewSSHClient(raw *ssh.Client) (*SSHClient, error) {
|
||||
@@ -30,8 +33,18 @@ func NewSSHClient(raw *ssh.Client) (*SSHClient, error) {
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// Sudo 设置使用Sudo
|
||||
func (this *SSHClient) Sudo(password string) {
|
||||
this.sudo = true
|
||||
this.sudoPassword = password
|
||||
}
|
||||
|
||||
// Exec 执行shell命令
|
||||
func (this *SSHClient) Exec(cmd string) (stdout string, stderr string, err error) {
|
||||
if this.raw.User() != "root" && this.sudo {
|
||||
return this.execSudo(cmd, this.sudoPassword)
|
||||
}
|
||||
|
||||
session, err := this.raw.NewSession()
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
@@ -40,8 +53,8 @@ func (this *SSHClient) Exec(cmd string) (stdout string, stderr string, err error
|
||||
_ = session.Close()
|
||||
}()
|
||||
|
||||
stdoutBuf := bytes.NewBuffer([]byte{})
|
||||
stderrBuf := bytes.NewBuffer([]byte{})
|
||||
var stdoutBuf = &bytes.Buffer{}
|
||||
var stderrBuf = &bytes.Buffer{}
|
||||
session.Stdout = stdoutBuf
|
||||
session.Stderr = stderrBuf
|
||||
err = session.Run(cmd)
|
||||
@@ -51,6 +64,79 @@ func (this *SSHClient) Exec(cmd string) (stdout string, stderr string, err error
|
||||
return strings.TrimRight(stdoutBuf.String(), "\n"), stderrBuf.String(), nil
|
||||
}
|
||||
|
||||
// execSudo 使用sudo执行shell命令
|
||||
func (this *SSHClient) execSudo(cmd string, password string) (stdout string, stderr string, err error) {
|
||||
session, err := this.raw.NewSession()
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
defer func() {
|
||||
_ = session.Close()
|
||||
}()
|
||||
|
||||
modes := ssh.TerminalModes{
|
||||
ssh.ECHO: 0, // disable echo
|
||||
ssh.TTY_OP_ISPEED: 14400,
|
||||
ssh.TTY_OP_OSPEED: 14400,
|
||||
}
|
||||
|
||||
err = session.RequestPty("xterm", 80, 40, modes)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
var stderrBuf = &bytes.Buffer{}
|
||||
session.Stderr = stderrBuf
|
||||
|
||||
pipeIn, err := session.StdinPipe()
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
pipeOut, err := session.StdoutPipe()
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
var resultErr error
|
||||
var stdoutBuf = bytes.NewBuffer([]byte{})
|
||||
|
||||
go func() {
|
||||
var buf = make([]byte, 512)
|
||||
for {
|
||||
n, err := pipeOut.Read(buf)
|
||||
if n > 0 {
|
||||
if strings.Contains(string(buf[:n]), "[sudo] password for") {
|
||||
_, err = pipeIn.Write([]byte(password + "\n"))
|
||||
if err != nil {
|
||||
resultErr = err
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
stdoutBuf.Write(buf[:n])
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
err = session.Run("sudo " + cmd)
|
||||
|
||||
stdout = strings.TrimSpace(stdoutBuf.String())
|
||||
stderr = strings.TrimSpace(stderrBuf.String())
|
||||
|
||||
if err != nil {
|
||||
return stdout, stderr, err
|
||||
}
|
||||
|
||||
if resultErr != nil {
|
||||
return stdout, stderr, resultErr
|
||||
}
|
||||
return stdout, stderr, nil
|
||||
}
|
||||
|
||||
func (this *SSHClient) Listen(network string, addr string) (net.Listener, error) {
|
||||
return this.raw.Listen(network, addr)
|
||||
}
|
||||
@@ -152,3 +238,31 @@ func (this *SSHClient) WriteFile(path string, data []byte) (n int, err error) {
|
||||
func (this *SSHClient) Remove(path string) error {
|
||||
return this.sftp.Remove(path)
|
||||
}
|
||||
|
||||
// User 用户名
|
||||
func (this *SSHClient) User() string {
|
||||
return this.raw.User()
|
||||
}
|
||||
|
||||
// UserHome 用户地址
|
||||
func (this *SSHClient) UserHome() string {
|
||||
homeStdout, _, err := this.Exec("echo $HOME")
|
||||
if err != nil {
|
||||
return this.defaultUserHome()
|
||||
}
|
||||
|
||||
var home = strings.TrimSpace(homeStdout)
|
||||
if len(home) > 0 {
|
||||
return home
|
||||
}
|
||||
|
||||
return this.defaultUserHome()
|
||||
}
|
||||
|
||||
func (this *SSHClient) defaultUserHome() string {
|
||||
var user = this.raw.User()
|
||||
if user == "root" {
|
||||
return "/root"
|
||||
}
|
||||
return "/home/" + user
|
||||
}
|
||||
|
||||
82
internal/installers/ssh_client_test.go
Normal file
82
internal/installers/ssh_client_test.go
Normal file
@@ -0,0 +1,82 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package installers
|
||||
|
||||
import (
|
||||
"golang.org/x/crypto/ssh"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func testSSHClient(t *testing.T, username string, password string) *SSHClient {
|
||||
methods := []ssh.AuthMethod{}
|
||||
{
|
||||
authMethod := ssh.Password(password)
|
||||
methods = append(methods, authMethod)
|
||||
}
|
||||
|
||||
{
|
||||
authMethod := ssh.KeyboardInteractive(func(user, instruction string, questions []string, echos []bool) (answers []string, err error) {
|
||||
if len(questions) == 0 {
|
||||
return []string{}, nil
|
||||
}
|
||||
return []string{password}, nil
|
||||
})
|
||||
methods = append(methods, authMethod)
|
||||
}
|
||||
|
||||
config := &ssh.ClientConfig{
|
||||
User: username,
|
||||
Auth: methods,
|
||||
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
|
||||
return nil
|
||||
},
|
||||
Timeout: 5 * time.Second,
|
||||
}
|
||||
|
||||
sshClient, err := ssh.Dial("tcp", "192.168.2.31:22", config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
client, err := NewSSHClient(sshClient)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
func TestSSHClient_Home(t *testing.T) {
|
||||
var client = testSSHClient(t, "root", "123456")
|
||||
t.Log(client.UserHome())
|
||||
}
|
||||
|
||||
func TestSSHClient_Exec(t *testing.T) {
|
||||
var client = testSSHClient(t, "liuxiangchao", "123456")
|
||||
stdout, stderr, err := client.Exec("echo 'Hello'")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("stdout:", stdout, "stderr:", stderr)
|
||||
}
|
||||
|
||||
func TestSSHClient_SudoExec(t *testing.T) {
|
||||
var client = testSSHClient(t, "liuxiangchao", "123456")
|
||||
client.Sudo("123456")
|
||||
stdout, stderr, err := client.Exec("echo 'Hello'")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("stdout:", stdout, "stderr:", stderr)
|
||||
}
|
||||
|
||||
func TestSSHClient_SudoExec2(t *testing.T) {
|
||||
var client = testSSHClient(t, "liuxiangchao", "123456")
|
||||
client.Sudo("123456")
|
||||
stdout, stderr, err := client.Exec("/home/liuxiangchao/edge-node/edge-node/bin/edge-node start")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("stdout:", stdout, "stderr:", stderr)
|
||||
}
|
||||
@@ -26,7 +26,7 @@ func (this *NodeGrantService) CreateNodeGrant(ctx context.Context, req *pb.Creat
|
||||
|
||||
tx := this.NullTx()
|
||||
|
||||
grantId, err := models.SharedNodeGrantDAO.CreateGrant(tx, adminId, req.Name, req.Method, req.Username, req.Password, req.PrivateKey, req.Passphrase, req.Description, req.NodeId)
|
||||
grantId, err := models.SharedNodeGrantDAO.CreateGrant(tx, adminId, req.Name, req.Method, req.Username, req.Password, req.PrivateKey, req.Passphrase, req.Description, req.NodeId, req.Su)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -48,7 +48,7 @@ func (this *NodeGrantService) UpdateNodeGrant(ctx context.Context, req *pb.Updat
|
||||
|
||||
tx := this.NullTx()
|
||||
|
||||
err = models.SharedNodeGrantDAO.UpdateGrant(tx, req.NodeGrantId, req.Name, req.Method, req.Username, req.Password, req.PrivateKey, req.Passphrase, req.Description, req.NodeId)
|
||||
err = models.SharedNodeGrantDAO.UpdateGrant(tx, req.NodeGrantId, req.Name, req.Method, req.Username, req.Password, req.PrivateKey, req.Passphrase, req.Description, req.NodeId, req.Su)
|
||||
return this.Success()
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -59,6 +59,9 @@ var upgradeFuncs = []*upgradeVersion{
|
||||
{
|
||||
"0.3.3", upgradeV0_3_3,
|
||||
},
|
||||
{
|
||||
"0.3.7", upgradeV0_3_7,
|
||||
},
|
||||
}
|
||||
|
||||
// UpgradeSQLData 升级SQL数据
|
||||
@@ -532,3 +535,13 @@ func upgradeV0_3_3(db *dbs.DB) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// v0.3.7
|
||||
func upgradeV0_3_7(db *dbs.DB) error {
|
||||
// 修改所有edgeNodeGrants中的su为0
|
||||
_, err := db.Exec("UPDATE edgeNodeGrants SET su=0 WHERE su=1")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -21,7 +21,6 @@ func TestUpgradeSQLData(t *testing.T) {
|
||||
t.Log("ok")
|
||||
}
|
||||
|
||||
|
||||
func TestUpgradeSQLData_v0_3_1(t *testing.T) {
|
||||
db, err := dbs.NewInstanceFromConfig(&dbs.DBConfig{
|
||||
Driver: "mysql",
|
||||
@@ -68,4 +67,20 @@ func TestUpgradeSQLData_v0_3_3(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpgradeSQLData_v0_3_7(t *testing.T) {
|
||||
db, err := dbs.NewInstanceFromConfig(&dbs.DBConfig{
|
||||
Driver: "mysql",
|
||||
Dsn: "root:123456@tcp(127.0.0.1:3306)/db_edge?charset=utf8mb4&timeout=30s",
|
||||
Prefix: "edge",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = upgradeV0_3_7(db)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user