feat: OpenRC and runit init backends behind an Init interface
Extract init-neutral unit resolution into service/, add initsys.Init with systemd, openrc and runit backends, selected by 'init:' config or autodetect. OpenRC and runit are root only; rootless units run as system services as that user. Add docs and generated examples for all three.
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
// Package initsys selects the init system backend that installs and controls
|
||||
// unitdore services.
|
||||
package initsys
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/warkanum/unitdore/config"
|
||||
"github.com/warkanum/unitdore/openrc"
|
||||
"github.com/warkanum/unitdore/runit"
|
||||
"github.com/warkanum/unitdore/systemd"
|
||||
)
|
||||
|
||||
// Backend names.
|
||||
const (
|
||||
Systemd = "systemd"
|
||||
OpenRC = "openrc"
|
||||
Runit = "runit"
|
||||
)
|
||||
|
||||
// Init is implemented by every init system backend. u.User selects the scope;
|
||||
// backends that cannot do per-user managers run user units as system services.
|
||||
type Init interface {
|
||||
Name() string
|
||||
ServiceName(u config.Unit, prefix, suffix string) string
|
||||
UnitPath(u config.Unit, prefix, suffix string) (string, error)
|
||||
Generate(u config.Unit, prefix, suffix string) (string, error)
|
||||
Install(u config.Unit, prefix, suffix string) error
|
||||
Uninstall(u config.Unit, prefix, suffix string) error
|
||||
Enable(u config.Unit, prefix, suffix string) error
|
||||
Disable(u config.Unit, prefix, suffix string) error
|
||||
Start(u config.Unit, prefix, suffix string) error
|
||||
Stop(u config.Unit, prefix, suffix string) error
|
||||
// Status returns active | inactive | failed | activating | deactivating | unknown.
|
||||
Status(u config.Unit, prefix, suffix string) string
|
||||
IsInstalled(u config.Unit, prefix, suffix string) bool
|
||||
// SupportsLinger reports whether user units need systemd-style linger.
|
||||
SupportsLinger() bool
|
||||
}
|
||||
|
||||
// New returns the backend named in cfg.Init, or the detected one.
|
||||
func New(cfg *config.Config) (Init, error) {
|
||||
name := cfg.Init
|
||||
if name == "" {
|
||||
name = Detect("/")
|
||||
}
|
||||
switch name {
|
||||
case Systemd:
|
||||
return systemd.Backend{}, nil
|
||||
case OpenRC:
|
||||
return openrc.Backend{}, nil
|
||||
case Runit:
|
||||
return runit.Backend{ServiceDir: cfg.ServiceDir}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown init %q (want systemd, openrc or runit)", name)
|
||||
}
|
||||
}
|
||||
|
||||
// Detect guesses the running init system below root. Falls back to systemd.
|
||||
func Detect(root string) string {
|
||||
has := func(p string) bool {
|
||||
_, err := os.Stat(filepath.Join(root, p))
|
||||
return err == nil
|
||||
}
|
||||
switch {
|
||||
case has("run/systemd/system"):
|
||||
return Systemd
|
||||
case has("run/openrc"), has("sbin/openrc-run"):
|
||||
return OpenRC
|
||||
case has("run/runit"), has("etc/runit"):
|
||||
return Runit
|
||||
default:
|
||||
return Systemd
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user