Add SMTP healthcheck

Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
Knut Ahlers 2023-11-14 13:15:31 +01:00
parent 86b2b4943e
commit 171b80e751
Signed by: luzifer
GPG key ID: D91C3E91E4CAD6F5
2 changed files with 92 additions and 0 deletions

View file

@ -6,6 +6,7 @@ import (
"git.luzifer.io/luzifer/ipt-loadbalancer/pkg/config"
"git.luzifer.io/luzifer/ipt-loadbalancer/pkg/healthcheck/common"
"git.luzifer.io/luzifer/ipt-loadbalancer/pkg/healthcheck/http"
"git.luzifer.io/luzifer/ipt-loadbalancer/pkg/healthcheck/smtp"
"git.luzifer.io/luzifer/ipt-loadbalancer/pkg/healthcheck/tcp"
"github.com/Luzifer/go_helpers/v2/fieldcollection"
)
@ -25,6 +26,9 @@ func ByName(name string) Checker {
case "http":
return http.New()
case "smtp":
return smtp.New()
case "tcp":
return tcp.New()

View file

@ -0,0 +1,88 @@
// Package smtp contains a health-check to verify a SMTP server is
// indeed listening to SMTP protocol
package smtp
import (
"crypto/tls"
"fmt"
"net"
"net/smtp"
"time"
"git.luzifer.io/luzifer/ipt-loadbalancer/pkg/config"
"git.luzifer.io/luzifer/ipt-loadbalancer/pkg/healthcheck/common"
"github.com/Luzifer/go_helpers/v2/fieldcollection"
)
const (
settingInsecureTLS = "insecureTLS"
settingPort = "port"
settingTimeout = "timeout"
settingTLS = "tls"
)
type (
// Check represents the SMTP check
Check struct{}
)
var (
defInsecureTLS = false
defTimeout = time.Second
defTLS = false
)
// New returns a new SMTP check
func New() Check { return Check{} }
// Check executes the check
func (c Check) Check(settings *fieldcollection.FieldCollection, target config.Target) error {
conn, err := net.DialTimeout(
"tcp",
fmt.Sprintf("%s:%d", target.Addr, settings.MustInt64(settingPort, c.intToInt64Ptr(target.Port))),
settings.MustDuration(settingTimeout, &defTimeout),
)
if err != nil {
return fmt.Errorf("dialing tcp: %w", err)
}
sc, err := smtp.NewClient(conn, "localhost")
if err != nil {
return fmt.Errorf("creating SMTP client: %w", err)
}
if settings.MustBool(settingTLS, &defTLS) {
tc := &tls.Config{
InsecureSkipVerify: settings.MustBool(settingInsecureTLS, &defInsecureTLS), //nolint:gosec // That's intended
}
if err = sc.StartTLS(tc); err != nil {
return fmt.Errorf("starting TLS: %w", err)
}
}
if err = sc.Hello("localhost"); err != nil {
return fmt.Errorf("exchanging HELO: %w", err)
}
if err = sc.Close(); err != nil {
return fmt.Errorf("closing connection: %w", err)
}
return nil
}
// Help returns the set of settings used in the check
func (Check) Help() (help []common.SettingHelp) {
return []common.SettingHelp{
{Name: settingInsecureTLS, Default: defInsecureTLS, Description: "Skip TLS certificate validation"},
{Name: settingPort, Default: "target-port", Description: "Port to send the request to"},
{Name: settingTimeout, Default: defTimeout, Description: "Timeout for the HTTP request"},
{Name: settingTLS, Default: defTLS, Description: "Connect to port using TLS"},
}
}
func (Check) intToInt64Ptr(i int) *int64 {
i64 := int64(i)
return &i64
}