Files
NixMsg/cmd/nixmsg/healthcheck.go

77 lines
1.8 KiB
Go

package main
import (
"fmt"
"io"
"net"
"net/http"
"os"
"path/filepath"
"strings"
"time"
"git.asio.asia/nixevol/NixMsg/internal/config"
)
// healthcheck 请求本机 /healthz,成功退出 0。给 Docker HEALTHCHECK 用。
func cmdHealthcheck(_ []string) error {
cfgPath := config.PathFromEnv()
cfg, err := config.Load(cfgPath)
if err != nil {
// 无配置时仍尝试 data_dir 默认值下的 listen.addr
cfg = config.Default()
}
addr, err := resolveHealthAddr(cfg.DataDir, cfg.Listen)
if err != nil {
return err
}
url := "http://" + addr + "/healthz"
client := &http.Client{Timeout: 3 * time.Second}
resp, err := client.Get(url)
if err != nil {
return fmt.Errorf("healthcheck %s: %w", url, err)
}
defer func() { _ = resp.Body.Close() }()
_, _ = io.Copy(io.Discard, resp.Body)
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("healthcheck %s: status %d", url, resp.StatusCode)
}
return nil
}
func resolveHealthAddr(dataDir, listen string) (string, error) {
path := filepath.Join(dataDir, "listen.addr")
if b, err := os.ReadFile(path); err == nil {
addr := strings.TrimSpace(string(b))
if addr != "" {
return rewriteLoopback(addr), nil
}
}
if listen == "" {
return "", fmt.Errorf("no listen.addr and empty listen")
}
host, port, err := net.SplitHostPort(listen)
if err != nil {
// listen 可能是 ":7443"
if strings.HasPrefix(listen, ":") {
return "127.0.0.1" + listen, nil
}
return "", fmt.Errorf("parse listen %q: %w", listen, err)
}
if host == "" || host == "0.0.0.0" || host == "::" {
host = "127.0.0.1"
}
return net.JoinHostPort(host, port), nil
}
func rewriteLoopback(addr string) string {
host, port, err := net.SplitHostPort(addr)
if err != nil {
return addr
}
if host == "" || host == "0.0.0.0" || host == "::" {
host = "127.0.0.1"
}
return net.JoinHostPort(host, port)
}