mirror of
https://github.com/TeaOSLab/EdgeAPI.git
synced 2025-11-05 01:20:25 +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 创建认证信息
|
// 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 := NewNodeGrantOperator()
|
||||||
op.AdminId = adminId
|
op.AdminId = adminId
|
||||||
op.Name = name
|
op.Name = name
|
||||||
@@ -83,12 +83,12 @@ func (this *NodeGrantDAO) CreateGrant(tx *dbs.Tx, adminId int64, name string, me
|
|||||||
case "user":
|
case "user":
|
||||||
op.Username = username
|
op.Username = username
|
||||||
op.Password = password
|
op.Password = password
|
||||||
op.Su = false // TODO 需要做到前端可以配置
|
|
||||||
case "privateKey":
|
case "privateKey":
|
||||||
op.Username = username
|
op.Username = username
|
||||||
op.PrivateKey = privateKey
|
op.PrivateKey = privateKey
|
||||||
op.Passphrase = passphrase
|
op.Passphrase = passphrase
|
||||||
}
|
}
|
||||||
|
op.Su = su
|
||||||
op.Description = description
|
op.Description = description
|
||||||
op.NodeId = nodeId
|
op.NodeId = nodeId
|
||||||
op.State = NodeGrantStateEnabled
|
op.State = NodeGrantStateEnabled
|
||||||
@@ -97,7 +97,7 @@ func (this *NodeGrantDAO) CreateGrant(tx *dbs.Tx, adminId int64, name string, me
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdateGrant 修改认证信息
|
// 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 {
|
if grantId <= 0 {
|
||||||
return errors.New("invalid grantId")
|
return errors.New("invalid grantId")
|
||||||
}
|
}
|
||||||
@@ -111,12 +111,12 @@ func (this *NodeGrantDAO) UpdateGrant(tx *dbs.Tx, grantId int64, name string, me
|
|||||||
case "user":
|
case "user":
|
||||||
op.Username = username
|
op.Username = username
|
||||||
op.Password = password
|
op.Password = password
|
||||||
op.Su = false // TODO 需要做到前端可以配置
|
|
||||||
case "privateKey":
|
case "privateKey":
|
||||||
op.Username = username
|
op.Username = username
|
||||||
op.PrivateKey = privateKey
|
op.PrivateKey = privateKey
|
||||||
op.Passphrase = passphrase
|
op.Passphrase = passphrase
|
||||||
}
|
}
|
||||||
|
op.Su = su
|
||||||
op.Description = description
|
op.Description = description
|
||||||
op.NodeId = nodeId
|
op.NodeId = nodeId
|
||||||
err := this.Save(tx, op)
|
err := this.Save(tx, op)
|
||||||
|
|||||||
@@ -8,4 +8,5 @@ type Credentials struct {
|
|||||||
PrivateKey string
|
PrivateKey string
|
||||||
Passphrase string
|
Passphrase string
|
||||||
Method string
|
Method string
|
||||||
|
Sudo bool
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,7 +94,13 @@ func (this *BaseInstaller) Login(credentials *Credentials) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if credentials.Sudo {
|
||||||
|
client.Sudo(credentials.Password)
|
||||||
|
}
|
||||||
|
|
||||||
this.client = client
|
this.client = client
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,6 +152,10 @@ func (this *BaseInstaller) InstallHelper(targetDir string, role nodeconfigs.Node
|
|||||||
return env, err
|
return env, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(uname) == 0 {
|
||||||
|
return nil, errors.New("unable to execute 'uname -a' on this system")
|
||||||
|
}
|
||||||
|
|
||||||
osName := ""
|
osName := ""
|
||||||
archName := ""
|
archName := ""
|
||||||
if strings.Contains(uname, "Darwin") {
|
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"
|
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:
|
var data = []byte(`rpc:
|
||||||
endpoints: [ ${endpoints} ]
|
endpoints: [ ${endpoints} ]
|
||||||
nodeId: "${nodeId}"
|
nodeId: "${nodeId}"
|
||||||
@@ -108,7 +114,7 @@ secret: "${nodeSecret}"`)
|
|||||||
|
|
||||||
_, err = this.client.WriteFile(configFile, data)
|
_, err = this.client.WriteFile(configFile, data)
|
||||||
if err != nil {
|
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"
|
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:
|
var data = []byte(`rpc:
|
||||||
endpoints: [ ${endpoints} ]
|
endpoints: [ ${endpoints} ]
|
||||||
nodeId: "${nodeId}"
|
nodeId: "${nodeId}"
|
||||||
@@ -108,7 +114,7 @@ secret: "${nodeSecret}"`)
|
|||||||
|
|
||||||
_, err = this.client.WriteFile(configFile, data)
|
_, err = this.client.WriteFile(configFile, data)
|
||||||
if err != nil {
|
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) + "'")
|
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终端
|
// API终端
|
||||||
apiNodes, err := models.SharedAPINodeDAO.FindAllEnabledAndOnAPINodes(nil)
|
apiNodes, err := models.SharedAPINodeDAO.FindAllEnabledAndOnAPINodes(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -187,6 +169,7 @@ func (this *NodeQueue) InstallNode(nodeId int64, installStatus *models.NodeInsta
|
|||||||
PrivateKey: grant.PrivateKey,
|
PrivateKey: grant.PrivateKey,
|
||||||
Passphrase: grant.Passphrase,
|
Passphrase: grant.Passphrase,
|
||||||
Method: grant.Method,
|
Method: grant.Method,
|
||||||
|
Sudo: grant.Su == 1,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
installStatus.ErrorCode = "SSH_LOGIN_FAILED"
|
installStatus.ErrorCode = "SSH_LOGIN_FAILED"
|
||||||
@@ -196,6 +179,24 @@ func (this *NodeQueue) InstallNode(nodeId int64, installStatus *models.NodeInsta
|
|||||||
_ = installer.Close()
|
_ = 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)
|
err = installer.Install(installDir, params, installStatus)
|
||||||
return err
|
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) + "'")
|
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{}
|
installer := &NodeInstaller{}
|
||||||
err = installer.Login(&Credentials{
|
err = installer.Login(&Credentials{
|
||||||
Host: loginParams.Host,
|
Host: loginParams.Host,
|
||||||
@@ -277,6 +260,7 @@ func (this *NodeQueue) StartNode(nodeId int64) error {
|
|||||||
PrivateKey: grant.PrivateKey,
|
PrivateKey: grant.PrivateKey,
|
||||||
Passphrase: grant.Passphrase,
|
Passphrase: grant.Passphrase,
|
||||||
Method: grant.Method,
|
Method: grant.Method,
|
||||||
|
Sudo: grant.Su == 1,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -286,16 +270,16 @@ func (this *NodeQueue) StartNode(nodeId int64) error {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// 检查命令是否存在
|
// 检查命令是否存在
|
||||||
exeFile := installDir + "/edge-node/bin/edge-node"
|
exe, err := this.lookupNodeExe(node, installer.client)
|
||||||
_, err = installer.client.Stat(exeFile)
|
|
||||||
if err != nil {
|
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启动
|
// 我们先尝试Systemd启动
|
||||||
_, _, _ = installer.client.Exec("systemctl start edge-node")
|
_, _, _ = 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 {
|
if err != nil {
|
||||||
return errors.New("start failed: " + err.Error())
|
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) + "'")
|
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{}
|
installer := &NodeInstaller{}
|
||||||
err = installer.Login(&Credentials{
|
err = installer.Login(&Credentials{
|
||||||
Host: loginParams.Host,
|
Host: loginParams.Host,
|
||||||
@@ -383,6 +349,7 @@ func (this *NodeQueue) StopNode(nodeId int64) error {
|
|||||||
PrivateKey: grant.PrivateKey,
|
PrivateKey: grant.PrivateKey,
|
||||||
Passphrase: grant.Passphrase,
|
Passphrase: grant.Passphrase,
|
||||||
Method: grant.Method,
|
Method: grant.Method,
|
||||||
|
Sudo: grant.Su == 1,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -392,16 +359,16 @@ func (this *NodeQueue) StopNode(nodeId int64) error {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// 检查命令是否存在
|
// 检查命令是否存在
|
||||||
exeFile := installDir + "/edge-node/bin/edge-node"
|
exe, err := this.lookupNodeExe(node, installer.client)
|
||||||
_, err = installer.client.Stat(exeFile)
|
|
||||||
if err != nil {
|
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停止
|
// 我们先尝试Systemd停止
|
||||||
_, _, _ = installer.client.Exec("systemctl stop edge-node")
|
_, _, _ = 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 {
|
if err != nil {
|
||||||
return errors.New("stop failed: " + err.Error())
|
return errors.New("stop failed: " + err.Error())
|
||||||
}
|
}
|
||||||
@@ -411,3 +378,38 @@ func (this *NodeQueue) StopNode(nodeId int64) error {
|
|||||||
|
|
||||||
return nil
|
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) {
|
func TestQueue_InstallNode(t *testing.T) {
|
||||||
queue := NewQueue()
|
queue := NewNodeQueue()
|
||||||
err := queue.InstallNodeProcess(16, false)
|
err := queue.InstallNodeProcess(16, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
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) + "'")
|
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终端
|
// API终端
|
||||||
apiNodes, err := models.SharedAPINodeDAO.FindAllEnabledAndOnAPINodes(nil)
|
apiNodes, err := models.SharedAPINodeDAO.FindAllEnabledAndOnAPINodes(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -187,6 +169,7 @@ func (this *NSNodeQueue) InstallNode(nodeId int64, installStatus *models.NodeIns
|
|||||||
PrivateKey: grant.PrivateKey,
|
PrivateKey: grant.PrivateKey,
|
||||||
Passphrase: grant.Passphrase,
|
Passphrase: grant.Passphrase,
|
||||||
Method: grant.Method,
|
Method: grant.Method,
|
||||||
|
Sudo: grant.Su == 1,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
installStatus.ErrorCode = "SSH_LOGIN_FAILED"
|
installStatus.ErrorCode = "SSH_LOGIN_FAILED"
|
||||||
@@ -196,6 +179,24 @@ func (this *NSNodeQueue) InstallNode(nodeId int64, installStatus *models.NodeIns
|
|||||||
_ = installer.Close()
|
_ = 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)
|
err = installer.Install(installDir, params, installStatus)
|
||||||
return err
|
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) + "'")
|
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
|
installDir := node.InstallDir
|
||||||
if len(installDir) == 0 {
|
if len(installDir) == 0 {
|
||||||
@@ -264,27 +283,10 @@ func (this *NSNodeQueue) StartNode(nodeId int64) error {
|
|||||||
installDir = cluster.InstallDir
|
installDir = cluster.InstallDir
|
||||||
if len(installDir) == 0 {
|
if len(installDir) == 0 {
|
||||||
// 默认是 $登录用户/edge-dns
|
// 默认是 $登录用户/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"
|
exeFile := installDir + "/edge-dns/bin/edge-dns"
|
||||||
_, err = installer.client.Stat(exeFile)
|
_, 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) + "'")
|
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
|
installDir := node.InstallDir
|
||||||
if len(installDir) == 0 {
|
if len(installDir) == 0 {
|
||||||
@@ -370,27 +390,10 @@ func (this *NSNodeQueue) StopNode(nodeId int64) error {
|
|||||||
installDir = cluster.InstallDir
|
installDir = cluster.InstallDir
|
||||||
if len(installDir) == 0 {
|
if len(installDir) == 0 {
|
||||||
// 默认是 $登录用户/edge-dns
|
// 默认是 $登录用户/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"
|
exeFile := installDir + "/edge-dns/bin/edge-dns"
|
||||||
_, err = installer.client.Stat(exeFile)
|
_, err = installer.client.Stat(exeFile)
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ import (
|
|||||||
type SSHClient struct {
|
type SSHClient struct {
|
||||||
raw *ssh.Client
|
raw *ssh.Client
|
||||||
sftp *sftp.Client
|
sftp *sftp.Client
|
||||||
|
|
||||||
|
sudo bool
|
||||||
|
sudoPassword string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSSHClient(raw *ssh.Client) (*SSHClient, error) {
|
func NewSSHClient(raw *ssh.Client) (*SSHClient, error) {
|
||||||
@@ -30,8 +33,18 @@ func NewSSHClient(raw *ssh.Client) (*SSHClient, error) {
|
|||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sudo 设置使用Sudo
|
||||||
|
func (this *SSHClient) Sudo(password string) {
|
||||||
|
this.sudo = true
|
||||||
|
this.sudoPassword = password
|
||||||
|
}
|
||||||
|
|
||||||
// Exec 执行shell命令
|
// Exec 执行shell命令
|
||||||
func (this *SSHClient) Exec(cmd string) (stdout string, stderr string, err error) {
|
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()
|
session, err := this.raw.NewSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
@@ -40,8 +53,8 @@ func (this *SSHClient) Exec(cmd string) (stdout string, stderr string, err error
|
|||||||
_ = session.Close()
|
_ = session.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
stdoutBuf := bytes.NewBuffer([]byte{})
|
var stdoutBuf = &bytes.Buffer{}
|
||||||
stderrBuf := bytes.NewBuffer([]byte{})
|
var stderrBuf = &bytes.Buffer{}
|
||||||
session.Stdout = stdoutBuf
|
session.Stdout = stdoutBuf
|
||||||
session.Stderr = stderrBuf
|
session.Stderr = stderrBuf
|
||||||
err = session.Run(cmd)
|
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
|
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) {
|
func (this *SSHClient) Listen(network string, addr string) (net.Listener, error) {
|
||||||
return this.raw.Listen(network, addr)
|
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 {
|
func (this *SSHClient) Remove(path string) error {
|
||||||
return this.sftp.Remove(path)
|
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()
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -48,7 +48,7 @@ func (this *NodeGrantService) UpdateNodeGrant(ctx context.Context, req *pb.Updat
|
|||||||
|
|
||||||
tx := this.NullTx()
|
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()
|
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.3", upgradeV0_3_3,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"0.3.7", upgradeV0_3_7,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpgradeSQLData 升级SQL数据
|
// UpgradeSQLData 升级SQL数据
|
||||||
@@ -532,3 +535,13 @@ func upgradeV0_3_3(db *dbs.DB) error {
|
|||||||
|
|
||||||
return nil
|
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")
|
t.Log("ok")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func TestUpgradeSQLData_v0_3_1(t *testing.T) {
|
func TestUpgradeSQLData_v0_3_1(t *testing.T) {
|
||||||
db, err := dbs.NewInstanceFromConfig(&dbs.DBConfig{
|
db, err := dbs.NewInstanceFromConfig(&dbs.DBConfig{
|
||||||
Driver: "mysql",
|
Driver: "mysql",
|
||||||
@@ -69,3 +68,19 @@ func TestUpgradeSQLData_v0_3_3(t *testing.T) {
|
|||||||
}
|
}
|
||||||
t.Log("ok")
|
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