package cmpSnipper import ( "io" "bufio" "strings" "net" "golang.org/x/crypto/ssh" ) type cmpSshCliStruct struct { Host string Connect *ssh.Client Session *ssh.Session Output *bufio.Reader } func (app *App) SshAddHostKey(host string, remote net.Addr, pubKey ssh.PublicKey) error { app.Log(pubKey) return nil } func (app *App) SshConnReal(cmpSshCli *cmpSshCliStruct, host string, keyfile string) error { var err error cmpSshCli.Host = host key, err := app.FileReadLimit(keyfile, 1048576) if err != nil { app.Log(err) return err } signer, err := ssh.ParsePrivateKey(key) if err != nil { app.Log(err) return err } config := &ssh.ClientConfig{ User: "root", Auth: []ssh.AuthMethod{ // HostKeyCallback: InsecureIgnoreHostKey(), // ssh.Password("yourpassword"), ssh.PublicKeys(signer), }, // HostKeyCallback: ssh.FixedHostKey(hostKey), HostKeyCallback: ssh.HostKeyCallback(func(host string, remote net.Addr, key ssh.PublicKey) error { app.SshAddHostKey(host, remote, key) return nil }), } cmpSshCli.Connect, err = ssh.Dial("tcp", cmpSshCli.Host, config) if err != nil { app.Log(err) return err } return nil } func (app *App) SshSession(cmpSshCli *cmpSshCliStruct) error { var err error cmpSshCli.Session, err = cmpSshCli.Connect.NewSession() if err != nil { app.Log(err) return err } // defer cmpSshCli.Session.Close() modes := ssh.TerminalModes{ ssh.ECHO: 0, } err = cmpSshCli.Session.RequestPty("xterm", 50, 80, modes) if err != nil { app.Log(err) return err } // sshIn, err := session.StdinPipe() // if err != nil { // app.Log(err) // return err // } sshOut, err := cmpSshCli.Session.StdoutPipe() if err != nil { app.Log(err) return err } sshErr, err := cmpSshCli.Session.StderrPipe() if err != nil { app.Log(err) return err } output := io.MultiReader(sshOut, sshErr) cmpSshCli.Output = bufio.NewReader(output) return nil } func (app *App) SshConn(host string, keyfile string) (int, error) { var err error // app.Log(url) var cmpSshCli cmpSshCliStruct err = app.SshConnReal(&cmpSshCli, host, keyfile) if err != nil { return -1, err } err = app.SshSession(&cmpSshCli) if err != nil { return -1, err } app.SshList = append(app.SshList, cmpSshCli) app.Log("Append new") return len(app.SshList)-1, nil } func (app *App) SshExec(cmpWbsCli cmpWbsCliStruct, idx int, cma []string) (error) { var err error cmd := strings.Join(cma, " ") cmpSshCli := app.SshList[idx] // app.Log("idx: '%s', '%s'", idx, cmpSshCli.Host) err = cmpSshCli.Session.Start(cmd) if err != nil { app.Log(err) return err } res := map[string]interface{}{ "string": nil, } var bli []byte var sli string for { bli, _, err = cmpSshCli.Output.ReadLine() if err != nil { app.Log("Complete") break } sli = string(bli) app.Log(sli) res["string"] = sli app.HttpWebSockSendTo(cmpWbsCli, "cmpSshTest", res) } cmpSshCli.Session.Wait() app.Log("Free resource SshList[" + string(idx) + "]") cmpSshCli.Session.Close() cmpSshCli.Connect.Close() app.Log("Remove SshList[" + string(idx) + "]") var list []cmpSshCliStruct for i, li := range app.SshList { if i == idx { continue } list = append(list, li) } app.SshList = list app.Log("End") // done <- true return nil } func (app *App) CmpSshTestSnip(parm any) (any, error) { var err error // var ifcIM map[string]interface{} = parm cli, err := app.SnipGetCli(parm) // app.Log(cli) if err != nil { return map[string]interface{}{ "string": "Not client found", }, err } host, err := app.ConfGetStr("sshTestHost", "HostPort") if err != nil { return map[string]interface{}{ "string": "Not set sshTestHost.HostPort", }, err } keyfile, err := app.ConfGetStr("sshTestHost", "PrivateKeyFile") if err != nil { return map[string]interface{}{ "string": "Not set sshTestHost.PrivateKeyFile", }, err } cmi, err := app.ConfGetIfc("sshTestHost", "Command") if err != nil { return map[string]interface{}{ "string": "Not set sshTestHost.Command", }, err } cml := cmi.([]interface{}) cma := make([]string, len(cml)) for i, v := range cml { cma[i] = v.(string) } /* if cma[0] == "none" { return map[string]interface{}{ "string": "Can't get command", }, err } */ idx, err := app.SshConn(host, keyfile) if err != nil { return map[string]interface{}{ "string": "Connection to '" + host + "' failed", }, err } go func() { app.SshExec(cli, idx, cma) }() app.Log("Wait") return map[string]interface{}{ "string": "Launch: " + strings.Join(cma, " "), }, nil }