feat(SSH): Add support for SSH endpoint (#473)
* feat(SSH): Add support for SSH endpoint This commit adds support for SSH endpoint monitoring. Users can now configure an endpoint to be monitored using an SSH command by prefixing the endpoint's URL with ssh:\\. The configuration options for an SSH endpoint include the username, password, and command to be executed on the remote server. In addition, two placeholders are supported for SSH endpoints: [CONNECTED] and [STATUS]. This commit also updates the README to include instructions on how to configure SSH endpoints and the placeholders that can be used in their conditions. The README has been updated to include the new SSH-related options in the endpoints[] configuration object. Here's a summary of the changes made in this commit: Added support for SSH endpoint monitoring Updated the documentation to include instructions on how to configure SSH endpoints and the placeholders that can be used in their conditions
This commit is contained in:
@ -3,6 +3,7 @@ package client
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"golang.org/x/net/websocket"
|
||||
@ -17,6 +18,7 @@ import (
|
||||
"github.com/TwiN/whois"
|
||||
"github.com/ishidawataru/sctp"
|
||||
ping "github.com/prometheus-community/pro-bing"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -161,6 +163,74 @@ func CanPerformTLS(address string, config *Config) (connected bool, certificate
|
||||
return true, verifiedChains[0][0], nil
|
||||
}
|
||||
|
||||
// CanCreateSSHConnection checks whether a connection can be established and a command can be executed to an address
|
||||
// using the SSH protocol.
|
||||
func CanCreateSSHConnection(address, username, password string, config *Config) (bool, *ssh.Client, error) {
|
||||
var port string
|
||||
if strings.Contains(address, ":") {
|
||||
addressAndPort := strings.Split(address, ":")
|
||||
if len(addressAndPort) != 2 {
|
||||
return false, nil, errors.New("invalid address for ssh, format must be host:port")
|
||||
}
|
||||
address = addressAndPort[0]
|
||||
port = addressAndPort[1]
|
||||
} else {
|
||||
port = "22"
|
||||
}
|
||||
|
||||
cli, err := ssh.Dial("tcp", strings.Join([]string{address, port}, ":"), &ssh.ClientConfig{
|
||||
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||
User: username,
|
||||
Auth: []ssh.AuthMethod{
|
||||
ssh.Password(password),
|
||||
},
|
||||
Timeout: config.Timeout,
|
||||
})
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
return true, cli, nil
|
||||
}
|
||||
|
||||
// ExecuteSSHCommand executes a command to an address using the SSH protocol.
|
||||
func ExecuteSSHCommand(sshClient *ssh.Client, body string, config *Config) (bool, int, error) {
|
||||
type Body struct {
|
||||
Command string `json:"command"`
|
||||
}
|
||||
|
||||
defer sshClient.Close()
|
||||
|
||||
var b Body
|
||||
if err := json.Unmarshal([]byte(body), &b); err != nil {
|
||||
return false, 0, err
|
||||
}
|
||||
|
||||
sess, err := sshClient.NewSession()
|
||||
if err != nil {
|
||||
return false, 0, err
|
||||
}
|
||||
|
||||
err = sess.Start(b.Command)
|
||||
if err != nil {
|
||||
return false, 0, err
|
||||
}
|
||||
|
||||
defer sess.Close()
|
||||
|
||||
err = sess.Wait()
|
||||
if err == nil {
|
||||
return true, 0, nil
|
||||
}
|
||||
|
||||
e, ok := err.(*ssh.ExitError)
|
||||
if !ok {
|
||||
return false, 0, err
|
||||
}
|
||||
|
||||
return true, e.ExitStatus(), nil
|
||||
}
|
||||
|
||||
// Ping checks if an address can be pinged and returns the round-trip time if the address can be pinged
|
||||
//
|
||||
// Note that this function takes at least 100ms, even if the address is 127.0.0.1
|
||||
|
Reference in New Issue
Block a user