package client import ( "bytes" "fmt" "io/ioutil" "time" "git.loafle.net/commons_go/logging" cuej "git.loafle.net/commons_go/util/encoding/json" ocmsc "git.loafle.net/overflow/commons-go/model/sensorconfig" "golang.org/x/crypto/ssh" ) type SSHConfig struct { User string Auth []ssh.AuthMethod Host string Port int } type SSHClient struct { conf *SSHConfig } func (cli *SSHClient) Session() (*ssh.Session, error) { sshConfig := &ssh.ClientConfig{ User: cli.conf.User, Auth: cli.conf.Auth, HostKeyCallback: ssh.InsecureIgnoreHostKey(), Timeout: time.Second * 10, } addr := fmt.Sprintf("%s:%d", cli.conf.Host, cli.conf.Port) connection, err := ssh.Dial("tcp", addr, sshConfig) if err != nil { return nil, err } session, err := connection.NewSession() if err != nil { return nil, err } modes := ssh.TerminalModes{ ssh.ECHO: 0, // disable echoing ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud } if err := session.RequestPty("xterm", 80, 40, modes); err != nil { session.Close() return nil, err } return session, nil } func (cli *SSHClient) RunCommand(command string) ([]byte, error) { session, err := cli.Session() if nil != err { return nil, err } defer func() { session.Close() }() var b bytes.Buffer session.Stdout = &b logging.Logger().Debugf("%s \n", command) if err := session.Run(command); nil != err { return nil, err } return b.Bytes(), nil } func parsePrivateKey(keyPath, pw string) (ssh.Signer, error) { buff, err := ioutil.ReadFile(keyPath) if err != nil { return nil, err } if pw == "" { return ssh.ParsePrivateKey(buff) } return ssh.ParsePrivateKeyWithPassphrase(buff, []byte(pw)) } func New(target *ocmsc.Target) (*SSHClient, error) { connection := target.Connection auth := target.Auth ip := connection.IP port, _ := cuej.NumberToInt(connection.Port) user := auth["id"].(string) pw := auth["pw"].(string) keyFilePathObj := auth["keyFilePath"] keyFilePath := "" sshAuth := make([]ssh.AuthMethod, 0) if keyFilePathObj != nil { keyFilePath = keyFilePathObj.(string) if "" != keyFilePath { key, err := parsePrivateKey(keyFilePath, pw) if err != nil { return nil, err } sshAuth = append(sshAuth, ssh.PublicKeys(key)) } } sshAuth = append(sshAuth, ssh.Password(pw)) sshConf := &SSHConfig{ User: user, Auth: sshAuth, Host: ip, Port: port, } return &SSHClient{ conf: sshConf, }, nil }