diff --git a/internal/machine/corroservice/service.go b/internal/machine/corroservice/service.go index 6c0360ea..63bcb6d6 100644 --- a/internal/machine/corroservice/service.go +++ b/internal/machine/corroservice/service.go @@ -1,7 +1,9 @@ package corroservice +import "context" + type Service interface { - Start() error - Restart() error + Start(ctx context.Context) error + Restart(ctx context.Context) error Running() bool } diff --git a/internal/machine/corroservice/systemd.go b/internal/machine/corroservice/systemd.go index fb10185e..329de1a3 100644 --- a/internal/machine/corroservice/systemd.go +++ b/internal/machine/corroservice/systemd.go @@ -1,9 +1,11 @@ package corroservice import ( + "context" "fmt" "log/slog" "os/exec" + "time" ) const DefaultSystemdUnit = "uncloud-corrosion.service" @@ -21,22 +23,29 @@ func DefaultSystemdService(dataDir string) *SystemdService { } } -func (s *SystemdService) Start() error { - if _, err := exec.Command("systemctl", "start", s.Unit).Output(); err != nil { - return fmt.Errorf("systemctl start %s: %w", s.Unit, err) - } - slog.Info("Corrosion systemd service started.", "unit", s.Unit) - - // TODO: run a goroutine to check the status of the service and log any errors in the uncloud log. - s.running = true - return nil +func (s *SystemdService) Start(ctx context.Context) error { + return s.startOrRestart(ctx, "start") } -func (s *SystemdService) Restart() error { - if _, err := exec.Command("systemctl", "restart", s.Unit).Output(); err != nil { - return fmt.Errorf("systemctl restart %s: %w", s.Unit, err) +func (s *SystemdService) Restart(ctx context.Context) error { + return s.startOrRestart(ctx, "restart") +} + +func (s *SystemdService) startOrRestart(ctx context.Context, cmd string) error { + if _, err := exec.Command("systemctl", cmd, s.Unit).Output(); err != nil { + return fmt.Errorf("systemctl %s %s: %w", cmd, s.Unit, err) + } + slog.Info(fmt.Sprintf("Corrosion systemd service %sed.", cmd), "unit", s.Unit) + + // Optimistically wait for the corrosion service to start and initialise the database schema before proceeding. + timer := time.NewTimer(2 * time.Second) + defer timer.Stop() + + select { + case <-timer.C: + case <-ctx.Done(): + return nil } - slog.Info("Corrosion systemd service restarted.", "unit", s.Unit) // TODO: run a goroutine to check the status of the service and log any errors in the uncloud log. s.running = true diff --git a/internal/machine/machine.go b/internal/machine/machine.go index beeb217a..8e884679 100644 --- a/internal/machine/machine.go +++ b/internal/machine/machine.go @@ -170,7 +170,7 @@ func (m *Machine) Run(ctx context.Context) error { } slog.Info("Configured corrosion service.", "dir", m.config.CorrosionDir) - if err := m.config.CorrosionService.Start(); err != nil { + if err := m.config.CorrosionService.Start(ctx); err != nil { return fmt.Errorf("start corrosion service: %w", err) } } diff --git a/internal/machine/network.go b/internal/machine/network.go index b41ef2e0..d4034a1c 100644 --- a/internal/machine/network.go +++ b/internal/machine/network.go @@ -64,11 +64,11 @@ func (nc *networkController) Run(ctx context.Context) error { if nc.corroService.Running() { // Corrosion service was running before the WireGuard network was configured so we need to restart it. - if err := nc.corroService.Restart(); err != nil { + if err := nc.corroService.Restart(ctx); err != nil { return fmt.Errorf("restart corrosion service: %w", err) } } else { - if err := nc.corroService.Start(); err != nil { + if err := nc.corroService.Start(ctx); err != nil { return fmt.Errorf("start corrosion service: %w", err) } }