mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-21 10:43:36 +00:00
fix: Docker container data persistence issue (#249)
- Add GetDataDir() function to respect PULSE_DATA_DIR environment variable - Update all hardcoded /var/lib/pulse paths to use configurable data directory - Fix circular import by moving GetDataDir to utils package - Ensures Docker containers can properly persist configuration and alerts
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/rcourtman/pulse-go-rewrite/internal/models"
|
||||
"github.com/rcourtman/pulse-go-rewrite/internal/utils"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
@@ -188,9 +189,10 @@ type Manager struct {
|
||||
|
||||
// NewManager creates a new alert manager
|
||||
func NewManager() *Manager {
|
||||
alertsDir := filepath.Join(utils.GetDataDir(), "alerts")
|
||||
m := &Manager{
|
||||
activeAlerts: make(map[string]*Alert),
|
||||
historyManager: NewHistoryManager("/var/lib/pulse/alerts"),
|
||||
historyManager: NewHistoryManager(alertsDir),
|
||||
escalationStop: make(chan struct{}),
|
||||
alertRateLimit: make(map[string][]time.Time),
|
||||
recentAlerts: make(map[string]*Alert),
|
||||
@@ -1216,7 +1218,7 @@ func (m *Manager) SaveActiveAlerts() error {
|
||||
defer m.mu.RUnlock()
|
||||
|
||||
// Create directory if it doesn't exist
|
||||
alertsDir := "/var/lib/pulse/alerts"
|
||||
alertsDir := filepath.Join(utils.GetDataDir(), "alerts")
|
||||
if err := os.MkdirAll(alertsDir, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create alerts directory: %w", err)
|
||||
}
|
||||
@@ -1253,7 +1255,7 @@ func (m *Manager) LoadActiveAlerts() error {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
alertsFile := "/var/lib/pulse/alerts/active-alerts.json"
|
||||
alertsFile := filepath.Join(utils.GetDataDir(), "alerts", "active-alerts.json")
|
||||
data, err := os.ReadFile(alertsFile)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/rcourtman/pulse-go-rewrite/internal/utils"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
@@ -41,7 +42,7 @@ type HistoryManager struct {
|
||||
// NewHistoryManager creates a new history manager
|
||||
func NewHistoryManager(dataDir string) *HistoryManager {
|
||||
if dataDir == "" {
|
||||
dataDir = "/var/lib/pulse"
|
||||
dataDir = utils.GetDataDir()
|
||||
}
|
||||
|
||||
hm := &HistoryManager{
|
||||
|
||||
@@ -302,10 +302,28 @@ func (h *ConfigHandlers) HandleAddNode(w http.ResponseWriter, r *http.Request) {
|
||||
Msg("Added Proxmox cluster with auto-discovered endpoints")
|
||||
}
|
||||
} else {
|
||||
// Ensure user has realm for PBS
|
||||
// Parse PBS authentication details
|
||||
pbsUser := req.User
|
||||
if req.User != "" && !strings.Contains(req.User, "@") {
|
||||
pbsUser = req.User + "@pbs" // Default to @pbs realm if not specified
|
||||
pbsTokenName := req.TokenName
|
||||
|
||||
// Handle different token input formats
|
||||
if req.TokenName != "" && req.TokenValue != "" {
|
||||
// Check if token name contains the full format (user@realm!tokenname)
|
||||
if strings.Contains(req.TokenName, "!") {
|
||||
parts := strings.Split(req.TokenName, "!")
|
||||
if len(parts) == 2 {
|
||||
// Extract user from token ID if not already provided
|
||||
if pbsUser == "" {
|
||||
pbsUser = parts[0]
|
||||
}
|
||||
pbsTokenName = parts[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure user has realm for PBS (if using user/password or token with user)
|
||||
if pbsUser != "" && !strings.Contains(pbsUser, "@") {
|
||||
pbsUser = pbsUser + "@pbs" // Default to @pbs realm if not specified
|
||||
}
|
||||
|
||||
pbs := config.PBSInstance{
|
||||
@@ -313,7 +331,7 @@ func (h *ConfigHandlers) HandleAddNode(w http.ResponseWriter, r *http.Request) {
|
||||
Host: req.Host,
|
||||
User: pbsUser,
|
||||
Password: req.Password,
|
||||
TokenName: req.TokenName,
|
||||
TokenName: pbsTokenName,
|
||||
TokenValue: req.TokenValue,
|
||||
Fingerprint: req.Fingerprint,
|
||||
VerifySSL: req.VerifySSL,
|
||||
@@ -505,17 +523,35 @@ func (h *ConfigHandlers) HandleTestConnection(w http.ResponseWriter, r *http.Req
|
||||
}
|
||||
|
||||
// PBS test connection
|
||||
// Ensure user has realm for PBS
|
||||
// Parse PBS authentication details
|
||||
pbsUser := user
|
||||
if user != "" && !strings.Contains(user, "@") {
|
||||
pbsUser = user + "@pbs" // Default to @pbs realm if not specified
|
||||
pbsTokenName := tokenName
|
||||
|
||||
// Handle different token input formats
|
||||
if req.TokenName != "" && req.TokenValue != "" {
|
||||
// Check if token name contains the full format (user@realm!tokenname)
|
||||
if strings.Contains(req.TokenName, "!") && tokenName == req.TokenName {
|
||||
parts := strings.Split(req.TokenName, "!")
|
||||
if len(parts) == 2 {
|
||||
// Extract user from token ID if not already provided
|
||||
if pbsUser == "" {
|
||||
pbsUser = parts[0]
|
||||
}
|
||||
pbsTokenName = parts[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure user has realm for PBS (if using user/password or token with user)
|
||||
if pbsUser != "" && !strings.Contains(pbsUser, "@") {
|
||||
pbsUser = pbsUser + "@pbs" // Default to @pbs realm if not specified
|
||||
}
|
||||
|
||||
clientConfig := pbs.ClientConfig{
|
||||
Host: host,
|
||||
User: pbsUser,
|
||||
Password: req.Password,
|
||||
TokenName: tokenName,
|
||||
TokenName: pbsTokenName,
|
||||
TokenValue: req.TokenValue,
|
||||
VerifySSL: req.VerifySSL,
|
||||
Fingerprint: req.Fingerprint,
|
||||
|
||||
@@ -19,7 +19,7 @@ type Config struct {
|
||||
FrontendHost string `envconfig:"FRONTEND_HOST" default:"0.0.0.0"`
|
||||
FrontendPort int `envconfig:"FRONTEND_PORT" default:"7655"`
|
||||
ConfigPath string `envconfig:"CONFIG_PATH" default:"/etc/pulse"`
|
||||
DataPath string `envconfig:"DATA_PATH" default:"/data"`
|
||||
DataPath string `envconfig:"DATA_PATH" default:"/var/lib/pulse"`
|
||||
|
||||
// Proxmox VE connections
|
||||
PVEInstances []PVEInstance
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// GetDataDir returns the data directory path from environment or default
|
||||
func GetDataDir() string {
|
||||
if dir := os.Getenv("PULSE_DATA_DIR"); dir != "" {
|
||||
return dir
|
||||
}
|
||||
return "/var/lib/pulse"
|
||||
}
|
||||
+24
-6
@@ -48,13 +48,31 @@ type auth struct {
|
||||
|
||||
// NewClient creates a new PBS API client
|
||||
func NewClient(cfg ClientConfig) (*Client, error) {
|
||||
// Parse user and realm
|
||||
parts := strings.Split(cfg.User, "@")
|
||||
if len(parts) != 2 {
|
||||
return nil, fmt.Errorf("invalid user format, expected user@realm")
|
||||
var user, realm string
|
||||
|
||||
// For token auth, user might be empty or in a different format
|
||||
if cfg.TokenName != "" && cfg.TokenValue != "" {
|
||||
// Token authentication - user is optional
|
||||
if cfg.User != "" {
|
||||
parts := strings.Split(cfg.User, "@")
|
||||
if len(parts) == 2 {
|
||||
user = parts[0]
|
||||
realm = parts[1]
|
||||
} else {
|
||||
// If no realm specified, default to pbs
|
||||
user = cfg.User
|
||||
realm = "pbs"
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Password authentication - user@realm format is required
|
||||
parts := strings.Split(cfg.User, "@")
|
||||
if len(parts) != 2 {
|
||||
return nil, fmt.Errorf("invalid user format, expected user@realm")
|
||||
}
|
||||
user = parts[0]
|
||||
realm = parts[1]
|
||||
}
|
||||
user := parts[0]
|
||||
realm := parts[1]
|
||||
|
||||
// Create HTTP client with proper TLS configuration
|
||||
httpClient := tlsutil.CreateHTTPClient(cfg.VerifySSL, cfg.Fingerprint)
|
||||
|
||||
Reference in New Issue
Block a user