gdraheim / docker-systemctl-replacement

docker systemctl replacement - allows to deploy to systemd-controlled containers without starting an actual systemd daemon (e.g. centos7, ubuntu16)
European Union Public License 1.2
1.36k stars 397 forks source link

Implement support for `set-default` command #32

Closed IOOOTAlan closed 6 years ago

IOOOTAlan commented 6 years ago

Support for the get/set-default commands is currently missing.

This is their intended function:

Unit File Commands:
[...]
  get-default                     Get the name of the default target
  set-default NAME                Set the default target

I currently needed the set-default command to not error-out during a post-install script execution, so I merely added an empty set_default_modules function to the Systemctl class, like this:

    def set_default_modules(self, *modules):
        return ""

and was able to proceed further.

gdraheim commented 6 years ago

Interesting, I have never thought of anyone trying to change the default runlevel. As docker targets are generally "multi-user" they are trying to go for "graphical" ?

Anyway, if you like to then you can also provide a patch / pull request so that the idea gets attached to your effort and testing.

gdraheim commented 6 years ago

According to tecmint, one should also implement "isolate".

https://www.tecmint.com/change-runlevels-targets-in-systemd/

Other than that, the systemctl.py does already have a notion of a "self._default_target" that is used throughout the code. However, it is not enough to simply put the value of a "set-default" into that variable as the value is gone as soon as the systemctl.py call is done. To make it permanent one would have to create a file-location with the value and one would have to watch for the reboot time just like for status files now. May be one could abuse the status-file system for something like an init.service - which is something that I had in the planning for quite a time in order to ask the zombie-reaper for its status.

IOOOTAlan commented 6 years ago

Interesting, I have never thought of anyone trying to change the default runlevel. As docker targets are generally "multi-user" they are trying to go for "graphical" ?

Well, my use case is a little different: I'm using docker-systemctl-replacement in a chroot environment, where I'm setting up a complete root filesystem for creating an image for an embedded device. As I cannot run the chroot using the ideal systemd-nspawn because systemd is totally absent from my host or could not be usable in a CI setup, I have to manage those systemctl calls performed by various package postinstall scripts some way or another, ideally without having to patch every postinst script to make it work in my setup. Your project seems a good solution for my needs, although I don't need to really run any service in my chroot environment, while I just need to persist any filesystem changes related to service enablement/masking etc. performed by systemctl.

Anyway, if you like to then you can also provide a patch / pull request so that the idea gets attached to your effort and testing.

I'm not really that skilled in python development and, as just explained, for my use case I don't really need a full blown implementation of the missing parts in docker-systemctl-replacement. However, If I find the time during my free time (this is a work account), this implementation could be a good exercise in python programming. No promises, though :wink:

gdraheim commented 6 years ago

I have implemented the runlevel behaviour by create a symlink "default.target". That's actually what the real systemd's systemctl does as well.

However, the "system default" startup command does not check for that at the moment. Nor any other function.

test_1201 test_1211

gdraheim commented 6 years ago

Did you test it?

gdraheim commented 6 years ago

As a result, I'll keep the behaviour the upcoming version 1.4, so that systemctl.py does not check the runlevel all by itself.

414n commented 6 years ago

Hi,

I ran a few tests on this feature by testing it alongside the original implementation. Here are my findings:

  1. I think there's some issue in getting the default target (systemctl.old is the original systemctl binary):
# ls -l /lib/systemd/system/default.target
lrwxrwxrwx 1 root root 16 Jul 30 21:31 /lib/systemd/system/default.target -> graphical.target
# ls -l /etc/systemd/system/default.target
ls: cannot access '/etc/systemd/system/default.target': No such file or directory
# systemctl get-default
multi-user.target
# systemctl.old get-default
graphical.target
  1. the set-default command does not error out when run without an actual target argument:
# systemctl set-default
#
  1. the set-default command seems to not be able to actually set the default target to any existing target unit:
# find / -name \*.target
/usr/lib/systemd/user/exit.target
/usr/lib/systemd/user/sockets.target
/usr/lib/systemd/user/paths.target
/usr/lib/systemd/user/graphical-session.target
/usr/lib/systemd/user/smartcard.target
/usr/lib/systemd/user/shutdown.target
/usr/lib/systemd/user/printer.target
/usr/lib/systemd/user/busnames.target
/usr/lib/systemd/user/basic.target
/usr/lib/systemd/user/timers.target
/usr/lib/systemd/user/graphical-session-pre.target
/usr/lib/systemd/user/default.target
/usr/lib/systemd/user/bluetooth.target
/usr/lib/systemd/user/sound.target
/etc/systemd/system/multi-user.target.wants/remote-fs.target
/lib/systemd/system/reboot.target
/lib/systemd/system/multi-user.target.wants/getty.target
/lib/systemd/system/local-fs-pre.target
/lib/systemd/system/exit.target
/lib/systemd/system/rpcbind.target
/lib/systemd/system/mail-transport-agent.target
/lib/systemd/system/sockets.target
/lib/systemd/system/suspend.target
/lib/systemd/system/initrd-switch-root.target
/lib/systemd/system/local-fs.target
/lib/systemd/system/network.target
/lib/systemd/system/paths.target
/lib/systemd/system/initrd-fs.target
/lib/systemd/system/initrd.target
/lib/systemd/system/final.target
/lib/systemd/system/cryptsetup-pre.target
/lib/systemd/system/smartcard.target
/lib/systemd/system/runlevel0.target
/lib/systemd/system/shutdown.target
/lib/systemd/system/remote-fs.target
/lib/systemd/system/network-online.target
/lib/systemd/system/emergency.target
/lib/systemd/system/network-pre.target
/lib/systemd/system/nss-lookup.target
/lib/systemd/system/runlevel5.target
/lib/systemd/system/sigpwr.target
/lib/systemd/system/slices.target
/lib/systemd/system/hybrid-sleep.target
/lib/systemd/system/runlevel1.target
/lib/systemd/system/printer.target
/lib/systemd/system/kexec.target
/lib/systemd/system/busnames.target
/lib/systemd/system/poweroff.target
/lib/systemd/system/remote-fs-pre.target
/lib/systemd/system/halt.target
/lib/systemd/system/runlevel3.target
/lib/systemd/system/basic.target
/lib/systemd/system/getty.target
/lib/systemd/system/cryptsetup.target
/lib/systemd/system/timers.target
/lib/systemd/system/hibernate.target
/lib/systemd/system/initrd-root-fs.target
/lib/systemd/system/swap.target
/lib/systemd/system/sleep.target
/lib/systemd/system/runlevel6.target
/lib/systemd/system/runlevel2.target
/lib/systemd/system/rescue.target
/lib/systemd/system/nss-user-lookup.target
/lib/systemd/system/default.target
/lib/systemd/system/bluetooth.target
/lib/systemd/system/time-sync.target
/lib/systemd/system/graphical.target
/lib/systemd/system/ctrl-alt-del.target
/lib/systemd/system/multi-user.target
/lib/systemd/system/sysinit.target
/lib/systemd/system/umount.target
/lib/systemd/system/runlevel4.target
/lib/systemd/system/sound.target
/lib/systemd/system/system-update.target
/lib/systemd/system/sysinit.target.wants/cryptsetup.target
# systemctl set-default runlevel4.target
ERROR:systemctl:no such runlevel /etc/systemd/system/runlevel4.target
# systemctl.old set-default runlevel4.target
Created symlink /etc/systemd/system/default.target, pointing to /lib/systemd/system/multi-user.target.
# systemctl set-default sleep.target
ERROR:systemctl:no such runlevel /etc/systemd/system/sleep.target
# systemctl.old set-default sleep.target
Removed symlink /etc/systemd/system/default.target.
Created symlink /etc/systemd/system/default.target, pointing to /lib/systemd/system/sleep.target.
# systemctl set-default multi-user.target
ERROR:systemctl:no such runlevel /etc/systemd/system/multi-user.target
# systemctl.old set-default multi-user.target
Removed symlink /etc/systemd/system/default.target.
Created symlink /etc/systemd/system/default.target, pointing to /lib/systemd/system/multi-user.target.
gdraheim commented 6 years ago

Thanks a lot for testing. I found that systemctl.py had not been using the existing *.target files for the list of possible targets, so that may be responsible for some irritations. Actualy, inside a docker container a lot of targets are missing, so I had added a static (hard coded) list of targets to be sure that some basic commands do work.

In any case, when doing "systemctl set-default basic.target" you will see that it binds to some /usr/lib path by now.

Created symlink from /home/guidod/docker/docker-systemctl-replacement/tmp/tmp.test_1211/root/etc/systemd/system/default.target -> /usr/lib/systemd/system/basic.target