github.com/sealerio/sealer@v0.11.1-0.20240507115618-f4f89c5853ae/utils/ssh/ssh.go (about)

     1  // Copyright © 2021 Alibaba Group Holding Ltd.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package ssh
    16  
    17  import (
    18  	"fmt"
    19  	"net"
    20  	"time"
    21  
    22  	"github.com/imdario/mergo"
    23  	"github.com/sirupsen/logrus"
    24  
    25  	"github.com/sealerio/sealer/common"
    26  	v1 "github.com/sealerio/sealer/types/api/v1"
    27  	v2 "github.com/sealerio/sealer/types/api/v2"
    28  	netUtils "github.com/sealerio/sealer/utils/net"
    29  	"github.com/sealerio/sealer/utils/os/fs"
    30  )
    31  
    32  type Interface interface {
    33  	// Copy local files to remote host
    34  	// scp -r /tmp root@192.168.0.2:/root/tmp => Copy("192.168.0.2","tmp","/root/tmp")
    35  	// need check md5sum
    36  	Copy(host net.IP, srcFilePath, dstFilePath string) error
    37  	// CopyR copy remote host files to localhost
    38  	CopyR(host net.IP, srcFilePath, dstFilePath string) error
    39  	// CmdAsync exec command on remote host, and asynchronous return logs
    40  	CmdAsync(host net.IP, env map[string]string, cmd ...string) error
    41  	// Cmd exec command on remote host, and return combined standard output and standard error
    42  	Cmd(host net.IP, env map[string]string, cmd string) ([]byte, error)
    43  	// CmdToString exec command on remote host, and return spilt standard output and standard error
    44  	CmdToString(host net.IP, env map[string]string, cmd, spilt string) (string, error)
    45  	// IsFileExist check remote file exist or not
    46  	IsFileExist(host net.IP, remoteFilePath string) (bool, error)
    47  	// RemoteDirExist Remote file existence returns true, nil
    48  	RemoteDirExist(host net.IP, remoteDirpath string) (bool, error)
    49  	// GetPlatform Get remote platform
    50  	GetPlatform(host net.IP) (v1.Platform, error)
    51  	// Ping Ping remote host
    52  	Ping(host net.IP) error
    53  }
    54  
    55  type SSH struct {
    56  	AlsoToStdout bool
    57  	Encrypted    bool
    58  	User         string
    59  	Password     string
    60  	Port         string
    61  	PkFile       string
    62  	PkPassword   string
    63  	Timeout      *time.Duration
    64  	LocalAddress []net.Addr
    65  	Fs           fs.Interface
    66  }
    67  
    68  func NewSSHClient(ssh *v1.SSH, alsoToStdout bool) Interface {
    69  	if ssh.User == "" {
    70  		ssh.User = common.ROOT
    71  	}
    72  	address, err := netUtils.GetLocalHostAddresses()
    73  	if err != nil {
    74  		logrus.Warnf("failed to get local address: %v", err)
    75  	}
    76  	return &SSH{
    77  		AlsoToStdout: alsoToStdout,
    78  		Encrypted:    ssh.Encrypted,
    79  		User:         ssh.User,
    80  		Password:     ssh.Passwd,
    81  		Port:         ssh.Port,
    82  		PkFile:       ssh.Pk,
    83  		PkPassword:   ssh.PkPasswd,
    84  		LocalAddress: address,
    85  		Fs:           fs.NewFilesystem(),
    86  	}
    87  }
    88  
    89  // GetHostSSHClient is used to executed bash command and no std out to be printed.
    90  func GetHostSSHClient(hostIP net.IP, cluster *v2.Cluster) (Interface, error) {
    91  	for i := range cluster.Spec.Hosts {
    92  		for _, ip := range cluster.Spec.Hosts[i].IPS {
    93  			if hostIP.Equal(ip) {
    94  				if err := mergo.Merge(&cluster.Spec.Hosts[i].SSH, &cluster.Spec.SSH); err != nil {
    95  					return nil, err
    96  				}
    97  				return NewSSHClient(&cluster.Spec.Hosts[i].SSH, false), nil
    98  			}
    99  		}
   100  	}
   101  	return nil, fmt.Errorf("failed to get host ssh client: host ip %s not in hosts ip list", hostIP)
   102  }
   103  
   104  // NewStdoutSSHClient is used to show std out when execute bash command.
   105  func NewStdoutSSHClient(hostIP net.IP, cluster *v2.Cluster) (Interface, error) {
   106  	for i := range cluster.Spec.Hosts {
   107  		for _, ip := range cluster.Spec.Hosts[i].IPS {
   108  			if hostIP.Equal(ip) {
   109  				if err := mergo.Merge(&cluster.Spec.Hosts[i].SSH, &cluster.Spec.SSH); err != nil {
   110  					return nil, err
   111  				}
   112  				return NewSSHClient(&cluster.Spec.Hosts[i].SSH, true), nil
   113  			}
   114  		}
   115  	}
   116  	return nil, fmt.Errorf("failed to get host ssh client: host ip %s not in hosts ip list", hostIP)
   117  }