Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions initsystem/service_ops_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,62 @@ func TestRegistryDetection(t *testing.T) {
require.ErrorIs(t, err, initsystem.ErrNoInitSystem)
require.NoError(t, mr.NotReceived(rigtest.Contains("openrc")))
})

t.Run("SysVinit not detected when systemd is present", func(t *testing.T) {
reg := initsystem.NewRegistry()
initsystem.RegisterSysVinit(reg)

// A systemd host: /etc/init.d exists (LSB compat) but systemd is present.
// SysVinit must decline so it never shadows systemd.
mr := rigtest.NewMockRunner()
mr.ErrDefault = errExec
mr.AddCommandSuccess(rigtest.Contains("/etc/init.d"))
mr.AddCommandSuccess(rigtest.Contains("stat /run/systemd/system"))

_, err := reg.Get(mr)
require.ErrorIs(t, err, initsystem.ErrNoInitSystem)

// Assert SysVinit actually exercised both probes: it passed the
// /etc/init.d check and then declined on the systemd-present check. This
// keeps the test specific so it cannot pass without running the intended
// detection logic.
require.NoError(t, mr.Received(rigtest.Contains("/etc/init.d")))
require.NoError(t, mr.Received(rigtest.Contains("stat /run/systemd/system")))
})

// Regression test for https://github.com/k0sproject/rig/issues/409: in a mixed
// Linux+Windows cluster, a Windows host resolving first swaps WinSCM to the front
// of the shared factory slice, demoting Systemd behind SysVinit. A subsequently
// resolved systemd Linux host must still resolve to Systemd, not SysVinit.
t.Run("Systemd wins on a systemd host after a Windows host resolved first (issue #409)", func(t *testing.T) {
reg := initsystem.NewRegistry()
// Same order as DefaultRegistry.
initsystem.RegisterSystemd(reg)
initsystem.RegisterOpenRC(reg)
initsystem.RegisterUpstart(reg)
initsystem.RegisterSysVinit(reg)
initsystem.RegisterWinSCM(reg)
initsystem.RegisterRunit(reg)
initsystem.RegisterLaunchd(reg)

// Windows host resolves first -> WinSCM matches and is moved to the front.
win := rigtest.NewMockRunner()
win.Windows = true
mgr, err := reg.Get(win)
require.NoError(t, err)
assert.IsType(t, &initsystem.WinSCM{}, mgr)

// Ubuntu-like systemd host: both `stat /run/systemd/system` and
// `test -d /etc/init.d` succeed. Must resolve to Systemd.
ubuntu := rigtest.NewMockRunner()
ubuntu.ErrDefault = errExec
ubuntu.AddCommandSuccess(rigtest.Contains("stat /run/systemd/system"))
ubuntu.AddCommandSuccess(rigtest.Contains("/etc/init.d"))

mgr, err = reg.Get(ubuntu)
require.NoError(t, err)
assert.IsType(t, initsystem.Systemd{}, mgr)
})
}

// Compile-time interface checks.
Expand Down
15 changes: 12 additions & 3 deletions initsystem/sysvinit.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,20 @@ func (i SysVinit) DisableService(ctx context.Context, h cmd.ContextRunner, s str

// RegisterSysVinit registers SysVinit in a repository.
func RegisterSysVinit(repo *Registry) {
repo.Register(func(c cmd.ContextRunner) (ServiceManager, bool) {
if c.IsWindows() {
repo.Register(func(runner cmd.ContextRunner) (ServiceManager, bool) {
if runner.IsWindows() {
return nil, false
}
if c.ExecContext(context.Background(), "test -d /etc/init.d") != nil {
if runner.ExecContext(context.Background(), "test -d /etc/init.d") != nil {
return nil, false
}
// /etc/init.d exists on virtually every systemd distro too (kept for LSB
// compatibility), so the probe above is not specific enough on its own: it
// makes SysVinit match systemd hosts. Require systemd to be ABSENT as well,
// mirroring RegisterSystemd's probe, so a systemd host never resolves to
// SysVinit regardless of factory ordering in the shared registry.
// See https://github.com/k0sproject/rig/issues/409.
if runner.ExecContext(context.Background(), "stat /run/systemd/system") == nil {
return nil, false
}

Expand Down
Loading