mirror of
https://github.com/psviderski/uncloud.git
synced 2026-10-06 13:18:58 +00:00
107 lines
2.5 KiB
Go
107 lines
2.5 KiB
Go
package daemon
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"log/slog"
|
|
"net"
|
|
|
|
"github.com/coreos/go-systemd/activation"
|
|
systemd "github.com/coreos/go-systemd/daemon"
|
|
"github.com/psviderski/uncloud/internal/machine"
|
|
)
|
|
|
|
const systemdSocketUnit = "uncloud.socket"
|
|
|
|
type Daemon struct {
|
|
machine *machine.Machine
|
|
}
|
|
|
|
func New(dataDir string) (*Daemon, error) {
|
|
listeners, err := activation.ListenersWithNames()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("get systemd-activated sockets: %w", err)
|
|
}
|
|
|
|
listener, err := selectActivatedListener(listeners)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if listener != nil {
|
|
slog.Info("Using systemd-activated API socket.", "addr", listener.Addr().String())
|
|
}
|
|
|
|
config := &machine.Config{
|
|
DataDir: dataDir,
|
|
ClusterAPISockPath: machine.DefaultClusterAPISockPath,
|
|
ClusterAPIListener: listener,
|
|
}
|
|
mach, err := machine.NewMachine(config)
|
|
if err != nil {
|
|
initErr := fmt.Errorf("init machine: %w", err)
|
|
if listener != nil {
|
|
if closeErr := listener.Close(); closeErr != nil {
|
|
initErr = errors.Join(initErr, fmt.Errorf("close systemd-activated socket: %w", closeErr))
|
|
}
|
|
}
|
|
return nil, initErr
|
|
}
|
|
|
|
return &Daemon{
|
|
machine: mach,
|
|
}, nil
|
|
}
|
|
|
|
// selectActivatedListener returns the systemd activated listener. If systemd supplied multiple listeners,
|
|
// it returns the one associated with systemdSocketUnit.
|
|
func selectActivatedListener(listeners map[string][]net.Listener) (net.Listener, error) {
|
|
var activated []net.Listener
|
|
for _, named := range listeners {
|
|
activated = append(activated, named...)
|
|
}
|
|
|
|
if len(activated) == 0 {
|
|
return nil, nil
|
|
}
|
|
if len(activated) == 1 {
|
|
return activated[0], nil
|
|
}
|
|
|
|
named, ok := listeners[systemdSocketUnit]
|
|
if !ok || len(named) != 1 {
|
|
return nil, fmt.Errorf("expected one systemd-activated socket named '%s', received %d",
|
|
systemdSocketUnit, len(named))
|
|
}
|
|
|
|
// Close all other unused listeners.
|
|
for name, unused := range listeners {
|
|
if name == systemdSocketUnit {
|
|
continue
|
|
}
|
|
for _, l := range unused {
|
|
_ = l.Close()
|
|
}
|
|
}
|
|
|
|
return named[0], nil
|
|
}
|
|
|
|
func (d *Daemon) Run(ctx context.Context) error {
|
|
slog.Info("Starting machine.")
|
|
|
|
// Notify systemd that the daemon is ready when the machine is started.
|
|
go func() {
|
|
select {
|
|
case <-d.machine.Started():
|
|
_, err := systemd.SdNotify(false, systemd.SdNotifyReady)
|
|
if err != nil {
|
|
slog.Error("Failed to notify systemd that the daemon is ready.", "err", err)
|
|
}
|
|
case <-ctx.Done():
|
|
}
|
|
}()
|
|
|
|
return d.machine.Run(ctx)
|
|
}
|