Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

runit-void: add alternatives to runit-void to facilitate fast init switching #29115

Closed
wants to merge 1 commit into from

Conversation

heliocat
Copy link
Contributor

@heliocat heliocat commented Feb 28, 2021

The runit-void package handles multiple duties. Th first is being the
base system configuration for all mainline void linux installs. The
second is handling the population of ownership of the init and power
controls (/usr/bin/halt, /usr/bin/shutdown, and the init, poweroff, and
reboot symlinks). Since those commands are required to manage a system,
anybody who wants to experiment with an alternate init scheme needs to
either put their init control elsewhere or clean up after any reloads of
runit-void.

The structure here is to split the commands required to start or stop a
system away from the configuration and services that make up the core of
Void. Core functionality continues to be provided by runit-void but it
is adjusted to depend on a virutal package called "void-init" for the
init and power commands. In mainline Void systems "void-init" is
provided by runit-void-init, a subpackage built alongside runit-void,
however this change allows any package to provide that functionality
without breaking the core distribution configuration.

From a package management perspective runit-void-init provides void-init
and replaces void-init. This allows for a single-pass replacement of any
other void-init providers simply by installing runit-void-init.
Similarly, an alternative init package can be installed in a single pass
via the same mechanisms without explicitly defining all packages that it
needs to override.

General

Have the results of the proposed changes been tested?

  • I use the packages affected by the proposed changes on a regular basis and confirm this PR works for me
  • I generally don't use the affected packages but briefly tested this PR

It's technically a new package but mostly a rearrangement of functionality to allow for better experimentation.

@heliocat
Copy link
Contributor Author

@Gottox @ericonr (plus whoever else wants in on this action).

@st3r4g
Copy link
Contributor

st3r4g commented Feb 28, 2021

In my opinion this would be most cleanly solved by xbps-alternatives. But if void-linux/xbps#185 (xbps can't replace a real file with a symlink) is still a problem and no work is being done to solve it, then we're stuck with virtual packages.

That said, I'm interested to try this out.

@st3r4g
Copy link
Contributor

st3r4g commented Feb 28, 2021

Looks like this works (tested on a fakeroot for now):

diff --git a/srcpkgs/runit-void/template b/srcpkgs/runit-void/template
index c495a45a3d..86b0cc58e3 100644
--- a/srcpkgs/runit-void/template
+++ b/srcpkgs/runit-void/template
@@ -1,7 +1,7 @@
 # Template file for 'runit-void'
 pkgname=runit-void
 version=20200720
-revision=1
+revision=2
 wrksrc="void-runit-${version}"
 build_style=gnu-makefile
 short_desc="Void Linux runit scripts"
@@ -28,9 +28,21 @@ make_dirs="
  /etc/zzz.d/suspend 0755 root root
  /etc/zzz.d/resume 0755 root root"
 
+alternatives="
+ void-init:init:/usr/bin/runit-init
+ void-init:halt:/usr/bin/halt-runit
+ void-init:poweroff:/usr/bin/poweroff-runit
+ void-init:reboot:/usr/bin/reboot-runit
+ void-init:shutdown:/usr/bin/shutdown-runit
+"
+
 post_install() {
        vmkdir usr/bin
        mv ${DESTDIR}/usr/sbin/* ${DESTDIR}/usr/bin
+       mv ${DESTDIR}/usr/bin/halt ${DESTDIR}/usr/bin/halt-runit
+       mv ${DESTDIR}/usr/bin/poweroff ${DESTDIR}/usr/bin/poweroff-runit
+       mv ${DESTDIR}/usr/bin/reboot ${DESTDIR}/usr/bin/reboot-runit
+       mv ${DESTDIR}/usr/bin/shutdown ${DESTDIR}/usr/bin/shutdown-runit
        vconf ${FILESDIR}/hostname
        vconf ${FILESDIR}/os-release
        vconf ${FILESDIR}/locale.conf
@@ -40,7 +52,6 @@ post_install() {
        rm -f ${DESTDIR}/etc/runit/runsvdir/current
        rm -rf ${DESTDIR}/etc/runit/runsvdir/default
        rm -rf ${DESTDIR}/etc/runit/runsvdir/single
-       ln -s runit-init ${DESTDIR}/usr/bin/init
 }
 
 runit-void-apparmor_package() {

the files are being replaced by symlinks correctly.

@st3r4g
Copy link
Contributor

st3r4g commented Feb 28, 2021

Also, a virtual package approach would remove the other init's poweroff file, which you still need once to shutdown the running system...

@teldra
Copy link
Contributor

teldra commented Feb 28, 2021

@mobinmob might be intrested

@mobinmob
Copy link
Contributor

Thanks @teldra!
@heliocat has spoken a little about this solution in #s6. I will test it. Handling the switch in the packages/package manager is nice, especially if it is gets serious consideration from the void team.
Currently I am using a slightly altered version of your switch-initutils in the boot-66serv PR ;)

@ahesford
Copy link
Member

This is the wrong solution to a problem I'm not even sure exists. Almost everything in runit-void is tied to the assumption that runit is bringing up the system. The services in /etc/sv are only useful if runsvdir is used to manage system services, which is done by the scripts in /etc/runit. So keeping those separate from the init bits doesn't make sense. The same is true for the startup and teardown scripts in /etc/runit, which exist to be invoked by runit as PID 1.

About the only bits which might apply to alternatives to runit are /etc/hostname, /etc/locale.conf, /etc/os-release, /usr/lib/dracut/dracut.conf.d/10-runit-void.conf and, assuming alternatives like s6 are configured to invoke them, the trio of /etc/rc.* scripts. All you need to do here is move those files to another package. Maybe some of these belong in base-files; the Dracut configuration probably belongs in dracut.

Replacing runit with an alternative is a fine thing to do, but I don't think Void has the resources to provide any official support for swappable service management and init systems. Alternatives and virtual packages each cause problems that we probably don't want. To go down the path of runit altneratives, ignorepkg runit-void, install and configure what you want.

@heliocat
Copy link
Contributor Author

@st3r4g I hadn't gone with the alternatives route for a couple of reasons but it is definitely the cleaner approach. First, someone (it might have even been you) had mentioned in IRC that xbps-alternatives was buggy and so I didn't want to put something as critical as startup and shutdown on that. The second is that I don't know at what point alternatives become available in the life of a new system and I didn't want to break off the extra work to guarantee that /sbin/init was available on bootstrap and otherwise very minimal systems at every point in the lifecycle. I'd assumed that was the reason that runit-init was explicitly symlinked to init in the first place.

As for poweroff that's a very good point. I'm thinking that a hybrid approach might make the most sense: alternatives for halt, poweroff, reboot, and shutdown, and an explicit link for init. That way system boot will continue to work using the plumbing as it exists but everything else takes the more flexible route. That would still require there to be a subpackage for init itself which is kind of lame but it would make everything else pretty straight forward. Thoughts?

@st3r4g
Copy link
Contributor

st3r4g commented Feb 28, 2021

First, someone (it might have even been you) had mentioned in IRC that xbps-alternatives was buggy and so I didn't want to put something as critical as startup and shutdown on that.

Yes it was me. But virtual packages have similar issues too, and are generally avoided when possible. So I understand that committers would not want to take responsibilities for this.

The second is that I don't know at what point alternatives become available in the life of a new system

The symlink should be there as soon as it is installed, so I don't see the issue here... but maybe I'm missing something.

As a start it would be good to do what ahesford said and move away from runit-void things that should be elsewhere. The ignorepkg approach is better than nothing...

@heliocat
Copy link
Contributor Author

heliocat commented Mar 1, 2021

First, someone (it might have even been you) had mentioned in IRC that xbps-alternatives was buggy and so I didn't want to put something as critical as startup and shutdown on that.

Yes it was me. But virtual packages have similar issues too, and are generally avoided when possible. So I understand that committers would not want to take responsibilities for this.

The second is that I don't know at what point alternatives become available in the life of a new system

The symlink should be there as soon as it is installed, so I don't see the issue here... but maybe I'm missing something.

As a start it would be good to do what ahesford said and move away from runit-void things that should be elsewhere. The ignorepkg approach is better than nothing...

I've got a half written reply to aheford vis-a-vis moving away from runit-void but the gist of is that I agree but didn't want to break that work off as part of this, at least not as part of the initial PR. As for the symlink presence, the concern is really about the guarantees around when alternatives symlinks are present. The dependency graph guarantees that packages, and by extension binaries, will be present but I don't know if alternatives provide those same guarantees in all circumstances.

@st3r4g
Copy link
Contributor

st3r4g commented Mar 1, 2021

As for the symlink presence, the concern is really about the guarantees around when alternatives symlinks are present. The dependency graph guarantees that packages, and by extension binaries, will be present but I don't know if alternatives provide those same guarantees in all circumstances.

Pretty sure they do. The alternative is registered (and the symlink created) in the unpack phase, right after package files are unpacked:
https://github.com/void-linux/xbps/blob/01180f9cb60893c4a57935fda106b1d5f77e2b49/lib/package_unpack.c#L663

@heliocat
Copy link
Contributor Author

heliocat commented Mar 2, 2021

@ahesford, thanks for the reply. From a high-level standpoint a decent chunk of void-runit seems generic enough to be reused, only 2, crtlaltdel, halt.*, runsvdir, services, and shutdown* directly depend on runit. 3 relies on runit by default but the calls to sv can be elided in rc.conf pretty easily. Obviously the calling semantics are rooted in runit conventions but that's it. In a larger overhaul or future follow-on work if something like this was embraced I could see making an argument for moving a lot of the contents of void-runit into base-files (core-services, vlogger, zzz, etc) though it would probably make sense to make base-files a distinct package as opposed to part of void-packages.

Something that I've been trying hard to avoid is accidentally making a fork of the distribution. I know that there are other people using Void as a baseline for various supervision-based init alternatives and it's a management and maintenance overhead for each person to backport upstream changes into their bespoke derivatives. My goal with this PR (in whatever form it finally ends up taking) is to add just enough flexibility into the core distribution to facilitate letting people do these experiments and system drifts without having to fork or hold core parts of the distribution. That isn't to say it'll work perfectly without a shim, but managing a compatibility shim is a lot easier when you aren't fighting the package manager. Also, I'm not advocating that Void take on any support burden for people using these knobs, just just there isn't an expectation of support if someone uses alternatives to switch in a magical rust implementation of awk, and in making these knobs I've been trying to make sure to not add additional management overhead for the distro maintainers or the core system.

If there's a place with the documented pitfalls of alternatives and virtual packages that would be great. I did just find void-linux/xbps#318 which seems mildly terrifying but I am definitely interested in seeing what else there is. At the end of the day I'd like to get this merged, but I'd like to get it merged in the best format I can, and one that impacts the core Void maintainers the least.

@heliocat
Copy link
Contributor Author

heliocat commented Mar 3, 2021

Updated to use an alternatives-based approach since that seems generally less disastrous at least in local testing. It's got some gotchas that I'm still working through, though I think most of those are fixable at the xlint and documentation level.

@leahneukirchen
Copy link
Member

I think this is a useful feature in general, and while I'm not in support of maintaining multiple init systems as is, it will allow experimentation with s6-based systems more easily, and may provide a path forward for Void in this way.

@st3r4g
Copy link
Contributor

st3r4g commented Mar 7, 2021

maybe it would be better to rename x-runit to runit-x for consistency with runit-init

@heliocat
Copy link
Contributor Author

heliocat commented Mar 7, 2021

I considered namespacing the commands with the general init scheme name as a prefix (runit-shutdown, runit-halt, etc) originally for the same reason you suggested but decided that using the package name as a suffix was probably more user friendly. This way people can type shut to get all in-path shutdown providers (for example). It also means that there won't be a name collision in the future if runit-void picks up an "init" executable in the future. The other possibility I saw was to use the full package name as the identifier but runit-void-halt is pretty awkward with very little gain in usability.

@st3r4g
Copy link
Contributor

st3r4g commented Mar 8, 2021

yeah, I actually like it more as a suffix. Also, s6-{init,poweroff,...} would be bad because it would give the impression that they are actual members of the s6 suite. I wonder if we can rename runit-init to init-runit to fix this little inconsistency. Or maybe just leave as it is, since init is not even executed manually.

@heliocat
Copy link
Contributor Author

heliocat commented Mar 8, 2021

I'd leave it as is. runit-init is the expected name for the original init process as shipped by runit and changing that name would involve quite a lot of documentation fixup and maybe a spot of patching as well.

@st3r4g
Copy link
Contributor

st3r4g commented Mar 8, 2021

So, I gave this a try and didn't encounter any xbps-alternative bugs. However there is an issue when trying to shutdown with runit after switching the alternative to s6, because poweroff-runit doesn't work as is:

  1. It should be a symlink to halt-runit instead of halt
  2. halt-runit should be instructed to reboot/poweroff when invoked through reboot/poweroff-runit

@heliocat
Copy link
Contributor Author

heliocat commented Mar 9, 2021

Fixing the first is easy, the second will most likely involve patching the source to accept additional command names. I want to think on it a bit before making that change though since I'm not particularly keen on adding a patch and I'm hoping inspiration strikes.

@heliocat
Copy link
Contributor Author

heliocat commented Mar 9, 2021

I was hoping this could all be done in the template but it looks like no. This pull request now depends on void-linux/void-runit#70

Once that merges I'll update the template here with the new release version of void-runit.

@st3r4g
Copy link
Contributor

st3r4g commented Mar 12, 2021

Trying again with void-runit master and it looks pretty nice. The issues above are solved.
I'll give an overview how it works.
Suppose you have a package for s6-l-i:

xbps-install s6-linux-init

Installing it will add an alternative for void-init:

$ xbps-alternatives -g void-init -l
void-init
 - runit-void (current)
  - init:/usr/bin/runit-init
  - halt:/usr/bin/halt-runit
  - poweroff:/usr/bin/poweroff-runit
  - reboot:/usr/bin/reboot-runit
  - shutdown:/usr/bin/shutdown-runit
 - s6-linux-init
  - init:/usr/bin/init-s6
  - halt:/usr/bin/halt-s6
  - poweroff:/usr/bin/poweroff-s6
  - reboot:/usr/bin/reboot-s6
  - shutdown:/usr/bin/shutdown-s6

To boot into s6:

xbps-alternatives -s s6-linux-init void-init
reboot-runit

And to boot back to runit:

xbps-alternatives -s runit-void void-init
reboot-s6

In case init breaks, runit-void is always there so you can always init=/sbin/runit-init

@heliocat
Copy link
Contributor Author

Thanks for the independent check @st3r4g!

@heliocat
Copy link
Contributor Author

heliocat commented Mar 14, 2021

I'm updating the PR with the assumption that void-runit will be tagged with today's date. Hence the giant failure.

@heliocat heliocat force-pushed the runit-void-init branch 3 times, most recently from d762d08 to 429852e Compare March 14, 2021 18:54
@heliocat heliocat changed the title runit-void: split package into main package and init controls runit-void: add alternatives to runit-void to facilitate fast init switching Mar 16, 2021
@heliocat
Copy link
Contributor Author

Updated to not conflict with the recent 20210314 release version.

@heliocat
Copy link
Contributor Author

Pinging on merge or NAK of this PR. Locally everything works as expected without any alternatives messes or what have you:

Before installing 20210314_2:

[*] runit-void-20210314_1 Void Linux runit scripts
carbon:~/src/void-linux/void-packages/hostdir/binpkgs/runit-void-init$ file /usr/bin/{init,halt,poweroff,reboot,shutdown}*
/usr/bin/init:     symbolic link to runit-init
/usr/bin/halt:     ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=5ade3fa87e2766f5e9f58454c4d8b76576bd4599, for GNU/Linux 3.2.0, stripped
/usr/bin/poweroff: symbolic link to halt
/usr/bin/reboot:   symbolic link to halt
/usr/bin/shutdown: POSIX shell script, ASCII text executable

After installing 20210314_2:

[*] runit-void-20210314_2 Void Linux runit scripts
cathexis@carbon:~/src/void-linux/void-packages/hostdir/binpkgs/runit-void-init$ file /usr/bin/{init,halt,poweroff,reboot,shutdown}*
/usr/bin/init:           symbolic link to runit-init
/usr/bin/halt:           symbolic link to halt-runit
/usr/bin/halt-runit:     ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=f928eb0e2d3306e5d82cbd37a6f6ab2f5ab6e98e, for GNU/Linux 3.2.0, stripped
/usr/bin/poweroff:       symbolic link to poweroff-runit
/usr/bin/poweroff-runit: symbolic link to halt-runit
/usr/bin/reboot:         symbolic link to reboot-runit
/usr/bin/reboot-runit:   symbolic link to halt-runit
/usr/bin/shutdown:       symbolic link to shutdown-runit
/usr/bin/shutdown-runit: POSIX shell script, ASCII text executable

Since there aren't any other packages currently providing alternatives for halt, init, poweroff, reboot, or shutdown, the problems noted in xbps#185, xbps#253, or void-packages#15836 are not blocking issues.

@Gottox
Copy link
Member

Gottox commented Apr 10, 2021

My 2 cents:

  • I have a love/hate relationship to the current alternatives implementation.
  • That said, alternatives are more for programs that make sense to be installed at the same time (think of vim vs neovim for example, or nvidia vs mesa) and you need to choose the default one. For init systems, this doesn't make sense, at least for me.
  • While I'm in favor of having the option to switch to other init systems, I'm strongly opposed to support more than one at a time. I disagree with @leahneukirchen, that alternatives bring any benefit when experimenting with alternatives to runit and instead just introduce more indirection.
  • for tinkering, replaces=runit... might be the better option here.

@heliocat
Copy link
Contributor Author

  • That said, alternatives are more for programs that make sense to be installed at the same time (think of vim vs neovim for example, or nvidia vs mesa) and you need to choose the default one. For init systems, this doesn't make sense, at least for me.

I'd argue that alternatives is the only mechanism that allows for safe replacement of the shutdown handlers while still leaving a recovery path if something goes wrong. Specifically in the case of runit-void vs s6-linux-init, the runit-void halt program primarily serves as a wrapper around calling runit-init with the correct arguments whereas s6-linux-init-hpr (intended to be symlinked as halt/poweroff/reboot) primarily functions as a mechanism to signal the shutdown service. Both have a force option that bypasses any handling, which allows runit-void's halt to shut down a s6-linux-init system (and vice versa), but down that road lies sadness and dataloss so I'd prefer to avoid it if at all possible.

  • While I'm in favor of having the option to switch to other init systems, I'm strongly opposed to support more than one at a time. I disagree with @leahneukirchen, that alternatives bring any benefit when experimenting with alternatives to runit and instead just introduce more indirection.
  • for tinkering, replaces=runit... might be the better option here.

I'm inclined to agree with the dislike of having more than one init but short of a hefty realignment of package contents there is a problem with that solution and that perspective. Specifically, runit (the suite) is two things: a process supervisor and half an init system (primarily pid 1). Similarly, runit-void is all of the low-level initialization policy mechanisms for Void and half of an init system (primarily the shutdown part). The initial form of this PR separated the runit-void shutdown programs into a subpackage but as @st3r4g mentioned that breaks the rollback guarantee of having the official binaries present in some form, as well as forcing users to use the -f options to bypass clean shutdown and instead directly signalling the kernel.

Regardless of what handles system lifecycle duties replacing the runit package isn't an option. First, it doesn't solve the halt, poweroff, reboot, or shutdown name collisions. But more importantly there are several packages with runtime dependencies on chpst, svlogd, or sv (mostly in the form of privilege dropping via chpst or calling sv check some_other_service) and replacing runit would instantly break those run scripts.

The runit-void package handles multiple duties. Th first is being the
base system configuration for all mainline void linux installs. The
second is handling the population of ownership of the init and power
controls (/usr/bin/halt, /usr/bin/shutdown, and the init, poweroff, and
reboot symlinks). Since those commands are required to manage a system,
anybody who wants to experiment with an alternate init scheme needs to
do one of: put their init control elsewhere, hold runit-void,  or clean
up after any reloads of runit-void.

This change adds the suffix `-runit` to shutdown, halt, poweroff, and
reboot and then registers shutdown, halt, poweroff, reboot, and init
names with alternatives under the void-init group. This will allow other
inits to take over for runit-void in a non-destructive fashion and
allows for easy rollbacks even in the face of disaster.

Thanks to st3r4g for pointing me towards xbps-alternatives instead of
using a virtual package to handle the ownership flip-flop. It is a much
cleaner method with significantly more straightforward semantics, though
not without its pitfalls.
@github-actions
Copy link

github-actions bot commented May 5, 2022

Pull Requests become stale 90 days after last activity and are closed 14 days after that. If this pull request is still relevant bump it or assign it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants