mirror of
https://github.com/hhftechnology/middleware-manager.git
synced 2025-12-20 15:59:38 -06:00
update
This commit is contained in:
172
main.go
172
main.go
@@ -25,43 +25,40 @@ type Plugin struct {
|
||||
IconPath string `json:"iconPath"`
|
||||
Import string `json:"import"`
|
||||
Summary string `json:"summary"`
|
||||
// Add any other fields that might be in your JSON, e.g., author, version
|
||||
Author string `json:"author,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
TestedWith string `json:"tested_with,omitempty"` // Example: "Traefik v2.10+"
|
||||
Stars int `json:"stars,omitempty"` // Example: GitHub stars
|
||||
Homepage string `json:"homepage,omitempty"` // Example: Link to plugin's GitHub repo
|
||||
Docs string `json:"docs,omitempty"` // Example: Link to plugin's documentation
|
||||
TestedWith string `json:"tested_with,omitempty"`
|
||||
Stars int `json:"stars,omitempty"`
|
||||
Homepage string `json:"homepage,omitempty"`
|
||||
Docs string `json:"docs,omitempty"`
|
||||
}
|
||||
|
||||
// Configuration represents the application configuration
|
||||
type Configuration struct {
|
||||
PangolinAPIURL string
|
||||
TraefikAPIURL string
|
||||
TraefikConfDir string
|
||||
DBPath string
|
||||
Port string
|
||||
UIPath string
|
||||
ConfigDir string
|
||||
CheckInterval time.Duration
|
||||
GenerateInterval time.Duration
|
||||
ServiceInterval time.Duration // New field for service check interval
|
||||
Debug bool
|
||||
AllowCORS bool
|
||||
CORSOrigin string
|
||||
ActiveDataSource string
|
||||
TraefikStaticConfigPath string // New: Path to traefik_config.yml or traefik.yml
|
||||
PluginsJSONURL string // New: URL to the plugins.json file
|
||||
PangolinAPIURL string
|
||||
TraefikAPIURL string
|
||||
TraefikConfDir string
|
||||
DBPath string
|
||||
Port string
|
||||
UIPath string
|
||||
ConfigDir string
|
||||
CheckInterval time.Duration
|
||||
GenerateInterval time.Duration
|
||||
ServiceInterval time.Duration
|
||||
Debug bool
|
||||
AllowCORS bool
|
||||
CORSOrigin string
|
||||
ActiveDataSource string
|
||||
TraefikStaticConfigPath string
|
||||
PluginsJSONURL string
|
||||
}
|
||||
|
||||
|
||||
// DiscoverTraefikAPI attempts to discover the Traefik API by trying common URLs
|
||||
func DiscoverTraefikAPI() (string, error) {
|
||||
client := &http.Client{
|
||||
Timeout: 2 * time.Second, // Short timeout for discovery
|
||||
Timeout: 2 * time.Second,
|
||||
}
|
||||
|
||||
// Common URLs to try
|
||||
urls := []string{
|
||||
"http://host.docker.internal:8080",
|
||||
"http://localhost:8080",
|
||||
@@ -81,22 +78,18 @@ func DiscoverTraefikAPI() (string, error) {
|
||||
resp.Body.Close()
|
||||
}
|
||||
}
|
||||
|
||||
return "", nil // Return empty string without error to allow fallbacks
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
log.Println("Starting Middleware Manager...")
|
||||
|
||||
// Parse command line flags
|
||||
var debug bool
|
||||
flag.BoolVar(&debug, "debug", false, "Enable debug mode")
|
||||
flag.Parse()
|
||||
|
||||
// Load configuration
|
||||
cfg := loadConfiguration(debug)
|
||||
|
||||
// Try to discover Traefik API URL if not set in environment
|
||||
if os.Getenv("TRAEFIK_API_URL") == "" {
|
||||
if discoveredURL, err := DiscoverTraefikAPI(); err == nil && discoveredURL != "" {
|
||||
log.Printf("Auto-discovered Traefik API URL: %s", discoveredURL)
|
||||
@@ -104,53 +97,51 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize database
|
||||
db, err := database.InitDB(cfg.DBPath)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to initialize database: %v", err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// Ensure config directory exists
|
||||
|
||||
configDir := cfg.ConfigDir
|
||||
if err := config.EnsureConfigDirectory(configDir); err != nil {
|
||||
log.Printf("Warning: Failed to create config directory: %v", err)
|
||||
}
|
||||
|
||||
// Save default templates file if it doesn't exist
|
||||
|
||||
if err := config.SaveTemplateFile(configDir); err != nil {
|
||||
log.Printf("Warning: Failed to save default templates: %v", err)
|
||||
}
|
||||
|
||||
// Load default middleware templates
|
||||
if err := config.LoadDefaultTemplates(db); err != nil {
|
||||
log.Printf("Warning: Failed to load default templates: %v", err)
|
||||
log.Printf("Warning: Failed to save default middleware templates: %v", err)
|
||||
}
|
||||
|
||||
if err := config.LoadDefaultTemplates(db); err != nil {
|
||||
log.Printf("Warning: Failed to load default middleware templates: %v", err)
|
||||
}
|
||||
|
||||
if err := config.SaveTemplateServicesFile(configDir); err != nil {
|
||||
log.Printf("Warning: Failed to save default service templates: %v", err)
|
||||
}
|
||||
|
||||
if err := config.LoadDefaultServiceTemplates(db); err != nil {
|
||||
log.Printf("Warning: Failed to load default service templates: %v", err)
|
||||
}
|
||||
|
||||
// Initialize config manager
|
||||
configManager, err := services.NewConfigManager(filepath.Join(configDir, "config.json"))
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to initialize config manager: %v", err)
|
||||
}
|
||||
|
||||
// Ensure default data sources are configured with potentially discovered URL
|
||||
configManager.EnsureDefaultDataSources(cfg.PangolinAPIURL, cfg.TraefikAPIURL)
|
||||
|
||||
// Create stop channel for graceful shutdown
|
||||
stopChan := make(chan struct{})
|
||||
|
||||
// Start resource watcher with config manager
|
||||
|
||||
resourceWatcher, err := services.NewResourceWatcher(db, configManager)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create resource watcher: %v", err)
|
||||
}
|
||||
go resourceWatcher.Start(cfg.CheckInterval)
|
||||
|
||||
// Start configuration generator
|
||||
configGenerator := services.NewConfigGenerator(db, cfg.TraefikConfDir, configManager)
|
||||
go configGenerator.Start(cfg.GenerateInterval)
|
||||
|
||||
// Start API server
|
||||
serverConfig := api.ServerConfig{
|
||||
Port: cfg.Port,
|
||||
UIPath: cfg.UIPath,
|
||||
@@ -158,20 +149,26 @@ func main() {
|
||||
AllowCORS: cfg.AllowCORS,
|
||||
CORSOrigin: cfg.CORSOrigin,
|
||||
}
|
||||
|
||||
// so handlers can access TraefikStaticConfigPath and PluginsJSONURL
|
||||
|
||||
server := api.NewServer(db.DB, serverConfig, configManager, cfg.TraefikStaticConfigPath, cfg.PluginsJSONURL)
|
||||
go func() {
|
||||
if err := server.Start(); err != nil {
|
||||
log.Printf("Server error: %v", err)
|
||||
close(stopChan) // Ensure stopChan is closed on server error
|
||||
close(stopChan)
|
||||
}
|
||||
}()
|
||||
|
||||
// Wait for shutdown signal or server error
|
||||
signalChan := make(chan os.Signal, 1)
|
||||
signal.Notify(signalChan, os.Interrupt, syscall.SIGTERM)
|
||||
|
||||
|
||||
serviceWatcher, err := services.NewServiceWatcher(db, configManager)
|
||||
if err != nil {
|
||||
log.Printf("Warning: Failed to create service watcher: %v", err)
|
||||
serviceWatcher = nil
|
||||
} else {
|
||||
go serviceWatcher.Start(cfg.ServiceInterval)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-signalChan:
|
||||
log.Println("Received shutdown signal")
|
||||
@@ -179,79 +176,70 @@ func main() {
|
||||
log.Println("Received stop signal from server")
|
||||
}
|
||||
|
||||
// Start service watcher with config manager
|
||||
serviceWatcher, err := services.NewServiceWatcher(db, configManager)
|
||||
if err != nil {
|
||||
log.Printf("Warning: Failed to create service watcher: %v", err)
|
||||
} else {
|
||||
// Use the same interval as the resource watcher, or a different one if preferred
|
||||
go serviceWatcher.Start(cfg.CheckInterval)
|
||||
}
|
||||
|
||||
// Graceful shutdown
|
||||
log.Println("Shutting down...")
|
||||
resourceWatcher.Stop()
|
||||
configGenerator.Stop()
|
||||
if serviceWatcher != nil { // Check if serviceWatcher was initialized
|
||||
if serviceWatcher != nil {
|
||||
serviceWatcher.Stop()
|
||||
}
|
||||
server.Stop() // Ensure server has a Stop method // Add this line
|
||||
configGenerator.Stop()
|
||||
server.Stop()
|
||||
log.Println("Middleware Manager stopped")
|
||||
}
|
||||
|
||||
// loadConfiguration loads configuration from environment variables
|
||||
func loadConfiguration(debug bool) Configuration {
|
||||
// Default check interval is 30 seconds
|
||||
checkInterval := 30 * time.Second
|
||||
if intervalStr := getEnv("CHECK_INTERVAL_SECONDS", "30"); intervalStr != "" {
|
||||
if interval, err := strconv.Atoi(intervalStr); err == nil && interval > 0 {
|
||||
checkInterval = time.Duration(interval) * time.Second
|
||||
}
|
||||
}
|
||||
|
||||
// Default generate interval is 10 seconds
|
||||
|
||||
generateInterval := 10 * time.Second
|
||||
if intervalStr := getEnv("GENERATE_INTERVAL_SECONDS", "10"); intervalStr != "" {
|
||||
if interval, err := strconv.Atoi(intervalStr); err == nil && interval > 0 {
|
||||
generateInterval = time.Duration(interval) * time.Second
|
||||
}
|
||||
}
|
||||
|
||||
// Allow CORS if specified
|
||||
|
||||
parsedServiceInterval := 30 * time.Second
|
||||
if intervalStr := getEnv("SERVICE_INTERVAL_SECONDS", "30"); intervalStr != "" {
|
||||
if interval, err := strconv.Atoi(intervalStr); err == nil && interval > 0 {
|
||||
parsedServiceInterval = time.Duration(interval) * time.Second
|
||||
}
|
||||
}
|
||||
|
||||
allowCORS := false
|
||||
if corsStr := getEnv("ALLOW_CORS", "false"); corsStr != "" {
|
||||
allowCORS = strings.ToLower(corsStr) == "true"
|
||||
}
|
||||
|
||||
// Override debug mode from environment if specified
|
||||
|
||||
if debugStr := getEnv("DEBUG", ""); debugStr != "" {
|
||||
debug = strings.ToLower(debugStr) == "true"
|
||||
}
|
||||
|
||||
|
||||
return Configuration{
|
||||
PangolinAPIURL: getEnv("PANGOLIN_API_URL", "http://pangolin:3001/api/v1"),
|
||||
// Changed to use host.docker.internal as first default to better support Docker environments
|
||||
TraefikAPIURL: getEnv("TRAEFIK_API_URL", "http://host.docker.internal:8080"),
|
||||
TraefikConfDir: getEnv("TRAEFIK_CONF_DIR", "/conf"),
|
||||
DBPath: getEnv("DB_PATH", "/data/middleware.db"),
|
||||
Port: getEnv("PORT", "3456"),
|
||||
UIPath: getEnv("UI_PATH", "/app/ui/build"),
|
||||
ConfigDir: getEnv("CONFIG_DIR", "/app/config"),
|
||||
ActiveDataSource: getEnv("ACTIVE_DATA_SOURCE", "pangolin"),
|
||||
CheckInterval: checkInterval,
|
||||
GenerateInterval: generateInterval,
|
||||
Debug: debug,
|
||||
AllowCORS: allowCORS,
|
||||
CORSOrigin: getEnv("CORS_ORIGIN", ""),
|
||||
TraefikStaticConfigPath: getEnv("TRAEFIK_STATIC_CONFIG_PATH", "/etc/traefik/traefik.yml"), // New
|
||||
PluginsJSONURL: getEnv("PLUGINS_JSON_URL", "https://raw.githubusercontent.com/hhftechnology/middleware-manager/traefik-int/plugin/plugins.json"), // New
|
||||
PangolinAPIURL: getEnv("PANGOLIN_API_URL", "http://pangolin:3001/api/v1"),
|
||||
TraefikAPIURL: getEnv("TRAEFIK_API_URL", "http://host.docker.internal:8080"),
|
||||
TraefikConfDir: getEnv("TRAEFIK_CONF_DIR", "/conf"),
|
||||
DBPath: getEnv("DB_PATH", "/data/middleware.db"),
|
||||
Port: getEnv("PORT", "3456"),
|
||||
UIPath: getEnv("UI_PATH", "/app/ui/build"),
|
||||
ConfigDir: getEnv("CONFIG_DIR", "/app/config"),
|
||||
ActiveDataSource: getEnv("ACTIVE_DATA_SOURCE", "pangolin"),
|
||||
CheckInterval: checkInterval,
|
||||
GenerateInterval: generateInterval,
|
||||
ServiceInterval: parsedServiceInterval,
|
||||
Debug: debug,
|
||||
AllowCORS: allowCORS,
|
||||
CORSOrigin: getEnv("CORS_ORIGIN", ""),
|
||||
TraefikStaticConfigPath: getEnv("TRAEFIK_STATIC_CONFIG_PATH", "/etc/traefik/traefik.yml"),
|
||||
PluginsJSONURL: getEnv("PLUGINS_JSON_URL", "https://raw.githubusercontent.com/hhftechnology/middleware-manager/traefik-int/plugin/plugins.json"),
|
||||
}
|
||||
}
|
||||
|
||||
// getEnv gets an environment variable or returns a default value
|
||||
func getEnv(key, fallback string) string {
|
||||
if value, exists := os.LookupEnv(key); exists {
|
||||
return value
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user