mirror of
https://github.com/labring/sealos.git
synced 2026-09-24 15:46:19 +08:00
refactor ssh client (#1381)
* perf: ssh client Signed-off-by: fengxsong <fengxsong@outlook.com> * fix: use channel to collect all the returned errors Signed-off-by: fengxsong <fengxsong@outlook.com>
This commit is contained in:
@@ -37,27 +37,28 @@ func (a HostChecker) Check(cluster *v2.Cluster, phase string) error {
|
||||
if len(a.IPs) != 0 {
|
||||
ipList = a.IPs
|
||||
}
|
||||
if err := checkHostnameUnique(cluster, ipList); err != nil {
|
||||
sshClient, err := ssh.NewSSHByCluster(cluster, false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("checker: failed to create ssh client, %v", err)
|
||||
}
|
||||
if err := checkHostnameUnique(sshClient, ipList); err != nil {
|
||||
return err
|
||||
}
|
||||
return checkTimeSync(cluster, ipList)
|
||||
return checkTimeSync(sshClient, ipList)
|
||||
}
|
||||
|
||||
func NewHostChecker() Interface {
|
||||
return &HostChecker{}
|
||||
}
|
||||
|
||||
func NewIPsHostChecker(ips []string) Interface {
|
||||
return &HostChecker{IPs: ips}
|
||||
}
|
||||
|
||||
func checkHostnameUnique(cluster *v2.Cluster, ipList []string) error {
|
||||
func checkHostnameUnique(s ssh.Interface, ipList []string) error {
|
||||
logger.Info("checker:hostname %v", ipList)
|
||||
hostnameList := map[string]bool{}
|
||||
for _, ip := range ipList {
|
||||
s, err := ssh.NewSSHByCluster(cluster, false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("checker: failed to get host %s hostname, %v", ip, err)
|
||||
}
|
||||
hostname, err := s.CmdToString(ip, "hostname", "")
|
||||
if err != nil {
|
||||
return fmt.Errorf("checker: failed to get host %s hostname, %v", ip, err)
|
||||
@@ -71,13 +72,9 @@ func checkHostnameUnique(cluster *v2.Cluster, ipList []string) error {
|
||||
}
|
||||
|
||||
//Check whether the node time is synchronized
|
||||
func checkTimeSync(cluster *v2.Cluster, ipList []string) error {
|
||||
func checkTimeSync(s ssh.Interface, ipList []string) error {
|
||||
logger.Info("checker:timeSync %v", ipList)
|
||||
for _, ip := range ipList {
|
||||
s, err := ssh.NewSSHByCluster(cluster, false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("checker: failed to get host %s hostname, %v", ip, err)
|
||||
}
|
||||
timeStamp, err := s.CmdToString(ip, "date +%s", "")
|
||||
if err != nil {
|
||||
return fmt.Errorf("checker: failed to get %s timestamp, %v", ip, err)
|
||||
|
||||
+22
-20
@@ -15,8 +15,10 @@
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -54,7 +56,8 @@ func NewSSHClient(ssh *v2.SSH, isStdout bool) Interface {
|
||||
if ssh.User == "" {
|
||||
ssh.User = v2.DefaultUserRoot
|
||||
}
|
||||
address, err := iputils.IsLocalHostAddrs()
|
||||
address, err := iputils.ListLocalHostAddrs()
|
||||
// todo: return error?
|
||||
if err != nil {
|
||||
logger.Warn("failed to get local address, %v", err)
|
||||
}
|
||||
@@ -69,29 +72,16 @@ func NewSSHClient(ssh *v2.SSH, isStdout bool) Interface {
|
||||
}
|
||||
|
||||
func NewSSHByCluster(cluster *v2.Cluster, isStdout bool) (Interface, error) {
|
||||
var (
|
||||
ipList []string
|
||||
)
|
||||
address, err := iputils.IsLocalHostAddrs()
|
||||
var ipList []string
|
||||
sshClient := NewSSHClient(&cluster.Spec.SSH, isStdout)
|
||||
if err != nil {
|
||||
logger.Warn("failed to get local address, %v", err)
|
||||
}
|
||||
ipList = append(ipList, append(cluster.GetIPSByRole(v2.Master), cluster.GetIPSByRole(v2.Node)...)...)
|
||||
|
||||
err = WaitSSHReady(sshClient, 6, ipList...)
|
||||
err := WaitSSHReady(sshClient, 6, ipList...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &SSH{
|
||||
isStdout: isStdout,
|
||||
User: cluster.Spec.SSH.User,
|
||||
Password: cluster.Spec.SSH.Passwd,
|
||||
PkFile: cluster.Spec.SSH.Pk,
|
||||
PkPassword: cluster.Spec.SSH.PkPasswd,
|
||||
LocalAddress: address,
|
||||
}, nil
|
||||
return sshClient, nil
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
@@ -100,22 +90,34 @@ type Client struct {
|
||||
}
|
||||
|
||||
func WaitSSHReady(ssh Interface, tryTimes int, hosts ...string) error {
|
||||
var err error
|
||||
errCh := make(chan error, len(hosts))
|
||||
var wg sync.WaitGroup
|
||||
for _, h := range hosts {
|
||||
wg.Add(1)
|
||||
go func(host string) {
|
||||
defer wg.Done()
|
||||
var err error
|
||||
for i := 0; i < tryTimes; i++ {
|
||||
err = ssh.Ping(host)
|
||||
if err == nil {
|
||||
errCh <- nil
|
||||
return
|
||||
}
|
||||
time.Sleep(time.Duration(i) * time.Second)
|
||||
}
|
||||
err = fmt.Errorf("wait for [%s] ssh ready timeout: %v, ensure that the IP address or password is correct", host, err)
|
||||
errCh <- fmt.Errorf("wait for [%s] ssh ready timeout: %v, ensure that the IP address or password is correct", host, err)
|
||||
}(h)
|
||||
}
|
||||
wg.Wait()
|
||||
return err
|
||||
close(errCh)
|
||||
var ret []string
|
||||
for err := range errCh {
|
||||
if err != nil {
|
||||
ret = append(ret, err.Error())
|
||||
}
|
||||
}
|
||||
if len(ret) > 0 {
|
||||
return errors.New(strings.Join(ret, ","))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ func GetHostIPSlice(hosts []string) (res []string) {
|
||||
return
|
||||
}
|
||||
|
||||
func IsLocalHostAddrs() (*[]net.Addr, error) {
|
||||
func ListLocalHostAddrs() (*[]net.Addr, error) {
|
||||
netInterfaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
logger.Warn("net.Interfaces failed, err:", err.Error())
|
||||
|
||||
Reference in New Issue
Block a user