mirror of
https://github.com/fosrl/newt.git
synced 2026-03-10 12:46:38 +00:00
Add health checks
This commit is contained in:
@@ -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
15
main.go
@@ -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(),
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user