Skip to content

Conversation

@msekletar
Copy link
Contributor

Right now it is difficult for distros to ship convenience/compat alias for some
service, e.g. mariadb aliased to mysql or nfs-server to nfs. If service which
comes with alias is not enabled by default then user must refer to its new unit
file name when trying to enable the service. Contrary, using alias for
start or stop works fine.

This patch introduces exception to current handling of enable requests. If we
find symlink instead of the unit file under /usr such that it has target in the
same directory, we then assume this is a convenience alias and we will follow
the symlink regardless the value of allow_symlink parameter.

Right now it is difficult for distros to ship convenience/compat alias for some
service, e.g. mariadb aliased to mysql or nfs-server to nfs. If service which
comes with alias is not enabled by default then user must refer to its new unit
file name when trying to enable the service. Contrary, using alias for
start or stop works fine.

This patch introduces exception to current handling of enable requests. If we
find symlink instead of the unit file under /usr such that it has target in the
same directory, we then assume this is a convenience alias and we will follow
the symlink regardless the value of allow_symlink parameter.
@msekletar msekletar added the RFE 🎁 Request for Enhancement, i.e. a feature request label Jun 2, 2015
@arvidjaar
Copy link
Contributor

So if bar.service is symlinked to foo.service, then

systemctl enable bar.service

will actually enable foo.service, right? And "is-enabled" for bar.service will actually check the "foo.service"?

@martinpitt
Copy link
Contributor

I must say, I'm not a big fan of this. It's quite a conscious design decision that alias names work for start/stop/disable, but not for enable as you really don't know what you are actually enabling precisely. Starting/stopping/disabling an alias is well-defined as it can only ever point to one "alternative", but enabling is not -- if you have two units (say mariadb.service and mysql-5.6.service) which both have Alias=mysql.service, which one will you get?

I understand that in your case you want to statically ship a symlink mysql.service → mysql-5.6.service in /usr/lib/systemd/system/. In this case this isn't really an Alias= in the usual sense, right? But how does that even help you? If multiple packages ship that symlink, then they need to conflict to each other anyway (i. e. aren't co-installable), so why not simplify this and just ship mysql.service as a actual file in all of them?

This is rather complicated code, so if this should get supported this should at least get a number of tests in src/test/test-install.c.

@msekletar
Copy link
Contributor Author

So if bar.service is symlinked to foo.service, then systemctl enable bar.service will actually enable foo.service, right?

Yes, that is correct.

And "is-enabled" for bar.service will actually check the "foo.service"?

There is an issue with is-enabled though. For example if your foo.service doesn't include in its [Install] section also Alias=bar.service then systemctl is-enabled bar.service will return disabled, even you enabled the foo.service via bar.service symlink. Having said that, I don't think this is problem in practice because intended use case for this feature is to provide user with possibility to use Alias name also for enable. Thus I assume that whoever provides such alias/compat symlink under /usr/ also makes sure that unit file also has Alias= set.

To be honest I didn't want to touch too much code, introducing logic which makes symlinks to unit files in /usr equivalent to unit files before I get some feedback on the general idea.

@msekletar
Copy link
Contributor Author

@martinpitt
This feature is in no way trying to provide/mimic concept of alternatives. It is really focused only on one very specific use case. Which is changing the name of some widely used service. E.g. mysql -> mariadb, so I wanted to make possible for package maintainers to provide administrator with more consistent experience if maintainer decides to ship mariadb unit file with Alias=mysql.service. Thus admin can use alias name for all common operations.

Truth is that I am not a big fan of all this either, but in the end I just gave up and wrote the patch, because I got tired of explaining people how things are supposed to work.

I will write tests if we decide we actually want this.

@arvidjaar
Copy link
Contributor

@msekletar
Such alias handling in systemd has fundamental problem that was discussed in relation to initscripts rewrite. Basically, in this case systemd will never see bar.service at all during transaction; so any dependency that may be configured for bar.service (and today with drop-ins it is easy to add them) will be ignored by systemd. So "systemctl enable bar.service" will give false impression that it is OK while it is actually not.

It is different from "systemctl start bar.service" where both names will be explicitly known and dependencies of both should be considered.

@emamirazavi
Copy link

I need this feature for the unit of my service. Exactly this feature. With
current systemd features, How can i alias mysql to mariadb?!

On Thu, Jun 4, 2015 at 1:08 PM, Andrey Borzenkov notifications@github.com
wrote:

@msekletar https://github.com/msekletar
Such alias handling in systemd has fundamental problem that was discussed
in relation to initscripts rewrite. Basically, in this case systemd will
never see bar.service at all during transaction; so any dependency that may
be configured for bar.service (and today with drop-ins it is easy to add
them) will be ignored by systemd. So "systemctl enable bar.service" will
give false impression that it is OK while it is actually not.

It is different from "systemctl start bar.service" where both names will
be explicitly known and dependencies of both should be considered.


Reply to this email directly or view it on GitHub
#40 (comment).

@johannbg
Copy link
Contributor

johannbg commented Jun 4, 2015

The answer to that is you dont alias mysql to mariadb,

@emamirazavi emamirazavi

This are two different databases with two different behaviours and administrators expect to be running either one and company's might even be paying oracle or other company's for support for either one ( which would then break ).

People might try to argue that this would be applicable during distribution "upgrades" where mysql ( or some other application ) was being deprecated from the distribution itself ( as was done in Fedora and failed miserably ) but they are wrong since components might be installed directly from upstream repository's or elsewhere.

If you want to play that dead end game then add something like "ln -s mariadb.service mysql.service" into the package which will create that "alias" and restart the systemd daemon to pick up those changes.

@emamirazavi
Copy link

Many thanks, I think your reply make vivid answer for this issue. Two
different behaviors! It means to distinguished services. In this case
suggested by Michael Sekletar, we won't need to these changes in systemd
source code. Will we?

On Thu, Jun 4, 2015 at 2:48 PM, Jóhann B. Guðmundsson <
notifications@github.com> wrote:

The answer to that is you dont alias mysql to mariadb,

@emamirazavi https://github.com/emamirazavi emamirazavi

This are two different databases with two different behaviours and
administrators expect to be running either one and company's might even be
paying oracle or other company's for support for either one ( which would
then break ).

People might try to argue that this would be applicable during
distribution "upgrades" where mysql ( or some other application ) was being
deprecated from the distribution itself ( as was done in Fedora and failed
miserably ) but they are wrong since components might be installed directly
from upstream repository's or elsewhere.
those where.

If you want to play that dead end game then add something like "ln -s
mariadb.service mysql.service" into the package which will create that
"alias" and restart the systemd daemon to pick up those changes.


Reply to this email directly or view it on GitHub
#40 (comment).

@msekletar
Copy link
Contributor Author

If you want to play that dead end game then add something like "ln -s mariadb.service mysql.service" into the package which will create that "alias" and restart the systemd daemon to pick up those changes.

@johannbg
The issue here is exactly about this symlink. Of course package maintainer adds that to rpm, deb or whatever but then clueless administrator is trying to start mysql and it works because we do follow symlinks when start is requested, nice, let's enable that so it starts automatically systemctl enable mysql and it doesn't work. That is surprising for people. In ideal world admin would of course know that mysql is no longer in the distro and he should sed through all his scripts and replace mysql with mariadb...too bad we don't live in such world.

@johannbg
Copy link
Contributor

johannbg commented Jun 4, 2015

@msekletar mariadb != mysql and administrator might be more shocked suddenly finding themselves having been migrated to a completely different application then they started out with, which is the root of that surprise since their expectation is to be running the application they started out with ( in this case mysql ) .

There are few usecases where this is legit ( think the deviation of unit names between distro's so distributions need to support the upstream unit name as well as their own name, httpd vs apache for example ) but that mysql/mariadb case is not one of them.

Arguably the solution here is showing the administrator he's starting an symlink which informs him of the actual type unit being worked with, which in turn will make things more consistent.

Something like...
systemctl start mysql.service
mysql.service is an symlink, redirecting to systemctl start mariadb.service

systemctl status mysql.service
mysql.service is an symlink, redirecting to systemctl status mariadb.service <--
● mariadb.service - MariaDB 10.0 database server <---
Loaded: loaded (/usr/lib/systemd/system/mariadb.service; disabled; vendor preset: disabled)
Active: active (running) since Thu 2015-06-04 10:03:58 GMT; 3s ago
....

@msekletar
Copy link
Contributor Author

@johannbg but the problem is not about start rather about enable. If maintainer decides to ship Alias= by default he just provides convenience for people who don't care what bits they run in the end.

What I am trying to get across is that if maintainer of service foo decides that providing the same service also under name bar is sane thing to do we should allow him to do so.

@johannbg
Copy link
Contributor

johannbg commented Jun 4, 2015

@msekletar it's irrelevant if it's start or enable right.

It should work the same for start/stop/restart/enable etc as in it should only work on/with the actual unit and just notify the administrator via useful message that he's working with symlink or alias as in

bar.service is an symlink, redirecting to systemctl start/stop/restart/enable/is-enabled etc foo.service

bar.service is an alias, redirecting to systemctl start/stop/restart/enable/is-enabled etc foo.service

Otherwise you end up causing confusion with administrators and creating to many problems than are being solved.

And with regards to the issue Matt points out as in if more then one unit is found with the same Alias, that alias should be refused to be used with an useful error msg to the administrator as in.

bar.service is an alias found in more then one unit refusing to start/stop/restart/enable/is-enabled etc.

@mbiebl
Copy link
Contributor

mbiebl commented Jun 4, 2015

2015-06-04 18:11 GMT+02:00 Jóhann B. Guðmundsson notifications@github.com:

@msekletar https://github.com/msekletar it's irrelevant if it's start
or enable right.

It should work the same for start/stop/restart/enable etc as in it should
only work on/with the actual unit and just notify the administrator via
useful message that he's working with symlink or alias as in

Related to that:
If you use "systemctl mask foo.service", and foo.service is a symlink too
the real unit file bar.service, systemctl will create a /dev/null symlink
for foo.service and not the actual unit file

Why is it that all of the instruments seeking intelligent life in the
universe are pointed away from Earth?

@msekletar
Copy link
Contributor Author

If you use "systemctl mask foo.service", and foo.service is a symlink too
the real unit file bar.service, systemctl will create a /dev/null symlink
for foo.service and not the actual unit file

I think this is intentional. We allow people to proactively mask unit files. If you request systemd to mask the unit it will not check anything and creates /dev/null link right away.

@johannbg
Copy link
Contributor

johannbg commented Jun 5, 2015

Hmm interesting so I have to ask why was it design that way as opposed to just deal with the actual unit file at all times, always for all alias, symlinks, label, tags etc?

@arvidjaar
Copy link
Contributor

@johannbg

bor@opensuse:~/src/systemd> sudo systemctl mask bar.service
bor@opensuse:~/src/systemd> sudo systemctl start bar.service
Failed to start bar.service: Unit bar.service is masked.
bor@opensuse:~/src/systemd> sudo systemctl unmask bar.service
bor@opensuse:~/src/systemd> sudo systemctl mask foo.service
bor@opensuse:~/src/systemd> sudo systemctl start bar.service
bor@opensuse:~/src/systemd> sudo systemctl show bar.service -p Names --no-pager
Names=bar.service foo.service
bor@opensuse:~/src/systemd> LC_ALL=C ll /run/systemd/system/*.service
lrwxrwxrwx 1 root root 11 Jun  6 11:03 /run/systemd/system/bar.service -> foo.service
-rw-r--r-- 1 root root 91 Jun  6 11:02 /run/systemd/system/foo.service

I'm afraid current handling of aliases through symlinks came to dead end. With existence of drop-ins it would be far easier to simply add foo.service.conf.d/alias-bar.conf with

[Unit]
Names=bar.service

This would avoid all problems associated with asymmetrical symlinks handling.

@msekletar
Copy link
Contributor Author

I am trying to figure out whether we even want this. @mezcalero any comments on this one. IIRC, you said you are in favor of such possibility.

@johannbg
Copy link
Contributor

johannbg commented Jun 8, 2015

Since I seem to be missing something it would be good to hear the logic for such favouritism as in what's the use case for aliases/symlinks beside backwards compatibility to previous service/unit names?

Why is it not enough to always work on the real name/real unit file and simply notify the administrator that it's what's being done when he uses the alias/symlink instead of the real-name?

What's the justification for the complication with the associated bugs, ( like for example what Martin and Michael Biebl point out ) broken behaviour and end user frustration that boils down to trying to chase down the alias/symlinks as an result of the complication with not always working only on the real unit file?

@msekletar
Copy link
Contributor Author

Since I seem to be missing something it would be good to hear the logic for such favouritism as in what's the use case for aliases/symlinks beside backwards compatibility to previous service/unit names?

Well, that is the use case. Providing convenience in case newly deployed service is backwards compatible so people don't have to go and fix their scripts.

Why is it not enough to always work on the real name/real unit file and simply notify the administrator that it's what's being done when he uses the alias/symlink instead of the real-name?

It is always enough to work on real/new unit file name.

What's the justification for the complication with the associated bugs, ( like for example what Martin and Michael Biebl point out ) broken behaviour and end user frustration that boils down to trying to chase down the alias/symlinks as an result of the complication with not always working only on the real unit file?

Sure there are bugs lurking in our installer code, especially in parts of it which are not exercised often by end user. But those can be fixed. Having said that, what @mbiebl pointed out is not a bug IMHO.

@johannbg
Copy link
Contributor

johannbg commented Jun 9, 2015

" Sure there are bugs lurking in our installer code, especially in parts of it which are not exercised often by end user. But those can be fixed. Having said that, what @mbiebl pointed out is not a bug IMHO."

Arguably it is. you should not be masking the symlink, you should be masking the real unit.

The only thing the code basically should be doing for all command is to check

if this is a symlink/alias, redirect the command to real unit and notify the administrator you are doing so,

if this is not a symlink/alias execute the command.

In your case you would never enable the alias or the symlink "mysql.service " but only the real unit "mariadb.service"

So when the administrator runs systemctl enable mysqld.service he would simply receive msg that said.
mysqld.service is an symlink, redirecting to systemctl enable mariadb.service

@msekletar
Copy link
Contributor Author

Ok, discussion under this PR is too moot and lengthy and scares away possible reviewers. I will try to rework a code a bit and also provide some test. Well, unless anyone comes up with sound argument why doing what this PR proposes is stupid idea.

@arvidjaar I don't think there is problem with depending on bar.service if you on top of symlink provide Alias=bar.service in the foo.service unit file. Or am I missing something?

@msekletar msekletar closed this Jun 12, 2015
@msekletar
Copy link
Contributor Author

Thanks for looking into this. I will rework as per your suggestions. FWIW, I tested the patch on instance units too. So if you have bar@.sevice -> foo@.service and should you call systemctl enable bar@baz.service indeed foo@baz.service will be enabled.

@msekletar
Copy link
Contributor Author

@poettering Sorry for the delay on v2, but it seems to me I've hit the dead end. Problem I am facing is with instance units.

Specifically, if I have getty-alias@.service -> getty@.service and if I enable getty@tty2.service using systemctl enable getty-alias@tty2.service there is no way to disable the getty@tty2.service via calling disable on alias.

This is because function which is marking symlinks for deletion is given instance_whitelist and if one calls systemctl disable getty-alias@tty2.service, then whitelist contains getty-alias@tty2.service however symlink under /etc has name getty@tty2.service hence is not on the whitelist and it is skipped.

@poettering
Copy link
Member

I am pretty sure we should make very clear that:

a) enabling/disabling a unit instance (i.e. a unit name with an "@" and a something following it) means we create/remove single instance symlink

b) enable/disabling any other unit (could be either a template unit, or a normal unit), means we honour the [install] section of the unit file, and do that following symlinks in /usr, but not /etc.

@msekletar
Copy link
Contributor Author

a) enabling/disabling a unit instance (i.e. a unit name with an "@" and a something following it) means we create/remove single instance symlink

Well, this is exactly how I envisioned things to work, but the problem I am having is with disable. Again, if I enable service instance via symlink in /usr I am not able to disable it the same way, i.e. via symlink name. This is because of instance_whitelist logic, i.e. symlink name is on whitelist but actual symlink in /etc was created with original name (which is a desired behavior imho) even though enable was done via symlink, but we followed symlink and figured out the proper name for the instance.

mischief added a commit to mischief/systemd that referenced this pull request Apr 6, 2016
networkd: rework idle detection logic of networkd
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

RFE 🎁 Request for Enhancement, i.e. a feature request

Development

Successfully merging this pull request may close these issues.

7 participants