package main import ( "context" "os" "os/signal" "syscall" "quickip/internal/config" "quickip/internal/deviceinfo" "quickip/internal/discovery" "quickip/internal/httpserver" "quickip/internal/logger" applyexecsvc "quickip/internal/network/applyexec" configreadersvc "quickip/internal/network/configreader" interfacesvc "quickip/internal/network/interfaces" netplansvc "quickip/internal/network/netplan" validatorsvc "quickip/internal/network/validator" "quickip/internal/systemaction" "quickip/internal/tasks" ) func main() { ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) defer stop() log := logger.New() cfg := config.Load(os.Args[1:]) if os.Geteuid() != 0 { log.Warn("agent is not running as root; netplan write/apply and system actions will fail") } deviceSvc := deviceinfo.New(cfg) interfaceSvc := interfacesvc.New(cfg) configSvc := configreadersvc.New() validatorSvc := validatorsvc.New() netplanSvc := netplansvc.New() applySvc := applyexecsvc.New() taskSvc := tasks.New() systemSvc := systemaction.New() if err := interfaceSvc.EnsureMaintenanceAddress(); err != nil { log.Error("failed to ensure maintenance address", "error", err.Error()) return } httpSrv := httpserver.New(cfg, log, deviceSvc, interfaceSvc, configSvc, validatorSvc, netplanSvc, applySvc, taskSvc, systemSvc) udpSrv := discovery.New(cfg, log, deviceSvc) errCh := make(chan error, 2) go func() { errCh <- httpSrv.Run(ctx) }() go func() { errCh <- udpSrv.Run(ctx) }() select { case <-ctx.Done(): log.Info("agent shutting down") case err := <-errCh: if err != nil { log.Error("agent stopped with error", "error", err.Error()) } } }