package main import ( "context" "os" "os/signal" "syscall" "time" "firewall_containers/network-go/config" "firewall_containers/network-go/docker" "firewall_containers/network-go/firewall" "firewall_containers/network-go/iptables" "firewall_containers/network-go/logger" "firewall_containers/network-go/watcher" ) // Config path - can be overridden via environment variable const defaultConfigPath = "/etc/user/config/networks.json" // Log path - can be overridden via environment variable const defaultLogPath = "/var/log/network-go/network-go.log" // Watch period - can be overridden via environment variable const defaultWatchPeriod = 30 * time.Second func getEnv(key, defaultVal string) string { if val := os.Getenv(key); val != "" { return val } return defaultVal } func getWatchPeriod() time.Duration { periodStr := os.Getenv("WATCH_PERIOD_SECONDS") if periodStr == "" { return defaultWatchPeriod } seconds, err := time.ParseDuration(periodStr + "s") if err != nil { logger.Warn("MAIN: invalid WATCH_PERIOD_SECONDS=%s, using default %s", periodStr, defaultWatchPeriod) return defaultWatchPeriod } return seconds } func getDebug() bool { return os.Getenv("DEBUG") == "1" || os.Getenv("DEBUG") == "true" } func main() { configPath := getEnv("NETWORKS_CONFIG_PATH", defaultConfigPath) logPath := getEnv("NETWORK_GO_LOG_PATH", defaultLogPath) watchPeriod := getWatchPeriod() debug := getDebug() // Initialize the dual-output logger (stdout + file) log := logger.NewLogger(debug, logPath) logger.SetDefault(log) log.Info("MAIN: starting network-go firewall container manager") log.Info("MAIN: config path = %s", configPath) log.Info("MAIN: log path = %s", logPath) log.Info("MAIN: watch period = %s", watchPeriod) log.Info("MAIN: debug = %v", debug) // Create Docker client (uses DOCKER_HOST env var automatically) dockerClient, err := docker.NewClient() if err != nil { log.Error("MAIN: failed to create Docker client: %v", err) os.Exit(1) } defer dockerClient.Close() log.Info("MAIN: Docker client created") // Create iptables manager iptablesMgr := iptables.NewManager(debug) log.Info("MAIN: iptables manager created (binary=%s)", iptablesMgr.Binary()) ctx := context.Background() // Load initial config cfg, err := config.Load(configPath) if err != nil { log.Error("MAIN: failed to load initial config: %v", err) os.Exit(1) } log.Info("MAIN: config loaded: %d networks, %d IPs, %d policies", len(cfg.Networks), len(cfg.IPs), len(cfg.Policies)) // Create the firewall orchestrator (needs config for resolver) orchestrator := firewall.NewOrchestrator(dockerClient, iptablesMgr, cfg) // Run full reconciliation orchestrator.ReconcileAll(ctx, cfg) // Set up file watcher to detect changes and re-reconcile onChange := func() { log.Info("MAIN: config file change detected, reloading and reconciling") newCfg, err := config.Load(configPath) if err != nil { log.Error("MAIN: failed to reload config: %v", err) return } log.Info("MAIN: config reloaded: %d networks, %d IPs, %d policies", len(newCfg.Networks), len(newCfg.IPs), len(newCfg.Policies)) orchestrator.ReconcileAll(ctx, newCfg) } fileWatcher := watcher.NewFileWatcher(configPath, watchPeriod, onChange) fileWatcher.Start() // Wait for shutdown signal sigCh := make(chan os.Signal, 1) signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) sig := <-sigCh log.Info("MAIN: received signal %v, shutting down", sig) fileWatcher.Stop() log.Info("MAIN: shutdown complete") }