error-pages/internal/cli/healthcheck/checker.go

90 lines
2.1 KiB
Go
Raw Normal View History

2024-07-03 14:12:13 +00:00
package healthcheck
import (
"context"
"crypto/tls"
"fmt"
"net/http"
"strings"
"time"
"gh.tarampamp.am/error-pages/internal/appmeta"
)
type (
httpClient interface {
Do(*http.Request) (*http.Response, error)
}
// HealthCheckerOption allows you to change some settings of the checker.
HealthCheckerOption func(*HTTPHealthChecker)
)
// WithHttpClient allows to set http client.
func WithHttpClient(c httpClient) HealthCheckerOption {
return func(hc *HTTPHealthChecker) { hc.httpClient = c }
}
// WithLiveEndpoint set the endpoint to check.
func WithLiveEndpoint(endpoint string) HealthCheckerOption {
if len(endpoint) > 0 && endpoint[0] != '/' {
endpoint = "/" + endpoint
}
return func(hc *HTTPHealthChecker) { hc.liveEndpoint = endpoint }
}
// HTTPHealthChecker is HTTP probe checker.
type HTTPHealthChecker struct {
httpClient httpClient
liveEndpoint string
}
var _ checker = (*HTTPHealthChecker)(nil) // ensure that HTTPHealthChecker implements checker interface
func NewHTTPHealthChecker(opts ...HealthCheckerOption) *HTTPHealthChecker {
const (
httpClientTimeout = 3 * time.Second
liveRoute = "/healthz"
)
var c = HTTPHealthChecker{
httpClient: &http.Client{
Timeout: httpClientTimeout,
Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}, //nolint:gosec
},
liveEndpoint: liveRoute,
}
for _, opt := range opts {
opt(&c)
}
return &c
}
// Check performs HTTP get request.
func (c *HTTPHealthChecker) Check(ctx context.Context, baseURL string) error {
var endpoint = strings.TrimRight(strings.TrimSpace(baseURL), "/") + c.liveEndpoint
var req, err = http.NewRequestWithContext(ctx, http.MethodGet, endpoint, http.NoBody)
if err != nil {
return err
}
req.Header.Set("User-Agent", fmt.Sprintf("ErrorPages/%s (HealthCheck)", appmeta.Version()))
resp, err := c.httpClient.Do(req)
if err != nil {
return err
}
_ = resp.Body.Close()
if code := resp.StatusCode; code != http.StatusOK && code != http.StatusNoContent {
return fmt.Errorf("wrong status code [%d] from the live endpoint (%s)", code, endpoint)
}
return nil
}