mirror of
https://github.com/gregtwallace/apc-p15-tool.git
synced 2025-01-22 08:14:08 +00:00
dda11df624
The code should auto-select the native ssl method if the ssl command is available on the UPS. If this fails, install will drop back to the original install method used by this tool (which works on NMC2).
91 lines
2.2 KiB
Go
91 lines
2.2 KiB
Go
package apcssh
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"golang.org/x/crypto/ssh"
|
|
)
|
|
|
|
// upsCmdResponse is a structure that holds all of a shell commands results
|
|
type upsCmdResponse struct {
|
|
command string
|
|
code string
|
|
codeText string
|
|
resultText string
|
|
}
|
|
|
|
// cmd creates an interactive shell and executes the specified command
|
|
func (cli *Client) cmd(command string) (*upsCmdResponse, error) {
|
|
// connect
|
|
sshClient, err := ssh.Dial("tcp", cli.hostname, cli.sshCfg)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("apcssh: failed to dial session (%w)", err)
|
|
}
|
|
defer sshClient.Close()
|
|
|
|
session, err := sshClient.NewSession()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("apcssh: failed to create session (%w)", err)
|
|
}
|
|
defer session.Close()
|
|
|
|
// pipes to send shell command to; and to receive repsonse
|
|
sshInput, err := session.StdinPipe()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("apcssh: failed to make shell input pipe (%w)", err)
|
|
}
|
|
sshOutput, err := session.StdoutPipe()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("apcssh: failed to make shell output pipe (%w)", err)
|
|
}
|
|
|
|
// make scanner to read shell continuously
|
|
scanner := bufio.NewScanner(sshOutput)
|
|
scanner.Split(scanAPCShell)
|
|
|
|
// start interactive shell
|
|
if err := session.Shell(); err != nil {
|
|
return nil, fmt.Errorf("apcssh: failed to start shell (%w)", err)
|
|
}
|
|
// discard the initial shell response (login message(s) / initial shell prompt)
|
|
for {
|
|
if token := scanner.Scan(); token {
|
|
_ = scanner.Bytes()
|
|
break
|
|
}
|
|
}
|
|
|
|
// send command
|
|
_, err = fmt.Fprint(sshInput, command+"\n")
|
|
if err != nil {
|
|
return nil, fmt.Errorf("apcssh: failed to send shell command (%w)", err)
|
|
}
|
|
|
|
res := &upsCmdResponse{}
|
|
for {
|
|
if tkn := scanner.Scan(); tkn {
|
|
result := string(scanner.Bytes())
|
|
|
|
cmdIndx := strings.Index(result, "\n")
|
|
res.command = result[:cmdIndx-1]
|
|
result = result[cmdIndx+1:]
|
|
|
|
codeIndx := strings.Index(result, ": ")
|
|
res.code = result[:codeIndx]
|
|
result = result[codeIndx+2:]
|
|
|
|
codeTxtIndx := strings.Index(result, "\n")
|
|
res.codeText = result[:codeTxtIndx-1]
|
|
|
|
// avoid out of bounds if no result text
|
|
if codeTxtIndx+1 <= len(result)-2 {
|
|
res.resultText = result[codeTxtIndx+1 : len(result)-2]
|
|
}
|
|
break
|
|
}
|
|
}
|
|
|
|
return res, nil
|
|
}
|