Add health checks

This commit is contained in:
Owen
2025-08-03 18:43:43 -07:00
parent e8612c7e6b
commit 289cce3a22
3 changed files with 46 additions and 25 deletions

View File

@@ -32,7 +32,7 @@ func (s Status) String() string {
// Config holds the health check configuration for a target // Config holds the health check configuration for a target
type Config struct { type Config struct {
ID string `json:"id"` ID int `json:"id"`
Enabled bool `json:"hcEnabled"` Enabled bool `json:"hcEnabled"`
Path string `json:"hcPath"` Path string `json:"hcPath"`
Scheme string `json:"hcScheme"` Scheme string `json:"hcScheme"`
@@ -59,11 +59,11 @@ type Target struct {
} }
// StatusChangeCallback is called when any target's status changes // StatusChangeCallback is called when any target's status changes
type StatusChangeCallback func(targets map[string]*Target) type StatusChangeCallback func(targets map[int]*Target)
// Monitor manages health check targets and their monitoring // Monitor manages health check targets and their monitoring
type Monitor struct { type Monitor struct {
targets map[string]*Target targets map[int]*Target
mutex sync.RWMutex mutex sync.RWMutex
callback StatusChangeCallback callback StatusChangeCallback
client *http.Client client *http.Client
@@ -72,7 +72,7 @@ type Monitor struct {
// NewMonitor creates a new health check monitor // NewMonitor creates a new health check monitor
func NewMonitor(callback StatusChangeCallback) *Monitor { func NewMonitor(callback StatusChangeCallback) *Monitor {
return &Monitor{ return &Monitor{
targets: make(map[string]*Target), targets: make(map[int]*Target),
callback: callback, callback: callback,
client: &http.Client{ client: &http.Client{
Timeout: 30 * time.Second, Timeout: 30 * time.Second,
@@ -118,7 +118,7 @@ func (m *Monitor) AddTargets(configs []Config) error {
for _, config := range configs { for _, config := range configs {
if err := m.addTargetUnsafe(config); err != nil { if err := m.addTargetUnsafe(config); err != nil {
return fmt.Errorf("failed to add target %s: %v", config.ID, err) return fmt.Errorf("failed to add target %d: %v", config.ID, err)
} }
} }
@@ -183,13 +183,13 @@ func (m *Monitor) addTargetUnsafe(config Config) error {
} }
// RemoveTarget removes a health check target // RemoveTarget removes a health check target
func (m *Monitor) RemoveTarget(id string) error { func (m *Monitor) RemoveTarget(id int) error {
m.mutex.Lock() m.mutex.Lock()
defer m.mutex.Unlock() defer m.mutex.Unlock()
target, exists := m.targets[id] target, exists := m.targets[id]
if !exists { if !exists {
return fmt.Errorf("target with id %s not found", id) return fmt.Errorf("target with id %d not found", id)
} }
target.cancel() target.cancel()
@@ -204,11 +204,11 @@ func (m *Monitor) RemoveTarget(id string) error {
} }
// RemoveTargets removes multiple health check targets // RemoveTargets removes multiple health check targets
func (m *Monitor) RemoveTargets(ids []string) error { func (m *Monitor) RemoveTargets(ids []int) error {
m.mutex.Lock() m.mutex.Lock()
defer m.mutex.Unlock() defer m.mutex.Unlock()
var notFound []string var notFound []int
for _, id := range ids { for _, id := range ids {
target, exists := m.targets[id] target, exists := m.targets[id]
@@ -234,20 +234,20 @@ func (m *Monitor) RemoveTargets(ids []string) error {
} }
// RemoveTargetsByID is a convenience method that accepts either a single ID or multiple IDs // RemoveTargetsByID is a convenience method that accepts either a single ID or multiple IDs
func (m *Monitor) RemoveTargetsByID(ids ...string) error { func (m *Monitor) RemoveTargetsByID(ids ...int) error {
return m.RemoveTargets(ids) return m.RemoveTargets(ids)
} }
// GetTargets returns a copy of all targets // GetTargets returns a copy of all targets
func (m *Monitor) GetTargets() map[string]*Target { func (m *Monitor) GetTargets() map[int]*Target {
m.mutex.RLock() m.mutex.RLock()
defer m.mutex.RUnlock() defer m.mutex.RUnlock()
return m.getAllTargetsUnsafe() return m.getAllTargetsUnsafe()
} }
// getAllTargetsUnsafe returns a copy of all targets without acquiring the mutex (internal method) // getAllTargetsUnsafe returns a copy of all targets without acquiring the mutex (internal method)
func (m *Monitor) getAllTargetsUnsafe() map[string]*Target { func (m *Monitor) getAllTargetsUnsafe() map[int]*Target {
targets := make(map[string]*Target) targets := make(map[int]*Target)
for id, target := range m.targets { for id, target := range m.targets {
// Create a copy to avoid race conditions // Create a copy to avoid race conditions
targetCopy := *target targetCopy := *target
@@ -257,7 +257,7 @@ func (m *Monitor) getAllTargetsUnsafe() map[string]*Target {
} }
// getAllTargets returns a copy of all targets (deprecated, use GetTargets) // getAllTargets returns a copy of all targets (deprecated, use GetTargets)
func (m *Monitor) getAllTargets() map[string]*Target { func (m *Monitor) getAllTargets() map[int]*Target {
return m.GetTargets() return m.GetTargets()
} }
@@ -363,17 +363,17 @@ func (m *Monitor) Stop() {
for _, target := range m.targets { for _, target := range m.targets {
target.cancel() target.cancel()
} }
m.targets = make(map[string]*Target) m.targets = make(map[int]*Target)
} }
// EnableTarget enables monitoring for a specific target // EnableTarget enables monitoring for a specific target
func (m *Monitor) EnableTarget(id string) error { func (m *Monitor) EnableTarget(id int) error {
m.mutex.Lock() m.mutex.Lock()
defer m.mutex.Unlock() defer m.mutex.Unlock()
target, exists := m.targets[id] target, exists := m.targets[id]
if !exists { if !exists {
return fmt.Errorf("target with id %s not found", id) return fmt.Errorf("target with id %d not found", id)
} }
if !target.Config.Enabled { if !target.Config.Enabled {
@@ -391,13 +391,13 @@ func (m *Monitor) EnableTarget(id string) error {
} }
// DisableTarget disables monitoring for a specific target // DisableTarget disables monitoring for a specific target
func (m *Monitor) DisableTarget(id string) error { func (m *Monitor) DisableTarget(id int) error {
m.mutex.Lock() m.mutex.Lock()
defer m.mutex.Unlock() defer m.mutex.Unlock()
target, exists := m.targets[id] target, exists := m.targets[id]
if !exists { if !exists {
return fmt.Errorf("target with id %s not found", id) return fmt.Errorf("target with id %d not found", id)
} }
if target.Config.Enabled { if target.Config.Enabled {

15
main.go
View File

@@ -338,6 +338,9 @@ func main() {
connected = false connected = false
} }
// print out the data
logger.Debug("Received registration message data: %+v", msg.Data)
jsonData, err := json.Marshal(msg.Data) jsonData, err := json.Marshal(msg.Data)
if err != nil { if err != nil {
logger.Info("Error marshaling data: %v", err) logger.Info("Error marshaling data: %v", err)
@@ -905,11 +908,11 @@ persistent_keepalive_interval=5`, fixKey(privateKey.String()), fixKey(wgData.Pub
}) })
// Initialize health check monitor with status change callback // Initialize health check monitor with status change callback
healthMonitor = healthcheck.NewMonitor(func(targets map[string]*healthcheck.Target) { healthMonitor = healthcheck.NewMonitor(func(targets map[int]*healthcheck.Target) {
logger.Debug("Health check status update for %d targets", len(targets)) logger.Debug("Health check status update for %d targets", len(targets))
// Send health status update to the server // Send health status update to the server
healthStatuses := make(map[string]interface{}) healthStatuses := make(map[int]interface{})
for id, target := range targets { for id, target := range targets {
healthStatuses[id] = map[string]interface{}{ healthStatuses[id] = map[string]interface{}{
"status": target.Status.String(), "status": target.Status.String(),
@@ -963,7 +966,7 @@ persistent_keepalive_interval=5`, fixKey(privateKey.String()), fixKey(wgData.Pub
logger.Debug("Received health check remove request: %+v", msg) logger.Debug("Received health check remove request: %+v", msg)
type HealthCheckConfig struct { type HealthCheckConfig struct {
IDs []string `json:"ids"` IDs []int `json:"ids"`
} }
var requestData HealthCheckConfig var requestData HealthCheckConfig
@@ -991,7 +994,7 @@ persistent_keepalive_interval=5`, fixKey(privateKey.String()), fixKey(wgData.Pub
logger.Debug("Received health check enable request: %+v", msg) logger.Debug("Received health check enable request: %+v", msg)
var requestData struct { var requestData struct {
ID string `json:"id"` ID int `json:"id"`
} }
jsonData, err := json.Marshal(msg.Data) jsonData, err := json.Marshal(msg.Data)
if err != nil { if err != nil {
@@ -1016,7 +1019,7 @@ persistent_keepalive_interval=5`, fixKey(privateKey.String()), fixKey(wgData.Pub
logger.Debug("Received health check disable request: %+v", msg) logger.Debug("Received health check disable request: %+v", msg)
var requestData struct { var requestData struct {
ID string `json:"id"` ID int `json:"id"`
} }
jsonData, err := json.Marshal(msg.Data) jsonData, err := json.Marshal(msg.Data)
if err != nil { if err != nil {
@@ -1041,7 +1044,7 @@ persistent_keepalive_interval=5`, fixKey(privateKey.String()), fixKey(wgData.Pub
logger.Debug("Received health check status request") logger.Debug("Received health check status request")
targets := healthMonitor.GetTargets() targets := healthMonitor.GetTargets()
healthStatuses := make(map[string]interface{}) healthStatuses := make(map[int]interface{})
for id, target := range targets { for id, target := range targets {
healthStatuses[id] = map[string]interface{}{ healthStatuses[id] = map[string]interface{}{
"status": target.Status.String(), "status": target.Status.String(),

View File

@@ -205,6 +205,15 @@ func (c *Client) getToken() (string, error) {
} }
} }
// Check for environment variable to skip TLS verification
if os.Getenv("SKIP_TLS_VERIFY") == "true" {
if tlsConfig == nil {
tlsConfig = &tls.Config{}
}
tlsConfig.InsecureSkipVerify = true
logger.Debug("TLS certificate verification disabled via SKIP_TLS_VERIFY environment variable")
}
var tokenData map[string]interface{} var tokenData map[string]interface{}
// Get a new token // Get a new token
@@ -339,6 +348,15 @@ func (c *Client) establishConnection() error {
} }
dialer.TLSClientConfig = tlsConfig dialer.TLSClientConfig = tlsConfig
} }
// Check for environment variable to skip TLS verification for WebSocket connection
if os.Getenv("SKIP_TLS_VERIFY") == "true" {
if dialer.TLSClientConfig == nil {
dialer.TLSClientConfig = &tls.Config{}
}
dialer.TLSClientConfig.InsecureSkipVerify = true
logger.Debug("WebSocket TLS certificate verification disabled via SKIP_TLS_VERIFY environment variable")
}
conn, _, err := dialer.Dial(u.String(), nil) conn, _, err := dialer.Dial(u.String(), nil)
if err != nil { if err != nil {
return fmt.Errorf("failed to connect to WebSocket: %w", err) return fmt.Errorf("failed to connect to WebSocket: %w", err)