[systemd-devel] Problem converting an rc script

John Lane systemd at jelmail.com
Mon Apr 8 05:06:41 PDT 2013


On 07/04/13 20:45, Mantas Mikulėnas wrote:
> On Sun, Apr 7, 2013 at 10:21 PM, John Lane <systemd at jelmail.com> wrote:
>> I have been trying to replace an rc script with a systemd unit file. It is
>> for an rvm (ruby version manager) environment and it starts a documentation
>> web server. I tried to create a service unit thus:
>>
>> [Service]
>> Type=forking
>> User=rvm
>> ExecStartPre=/bin/bash --login /etc/profile.d/rvm.sh
>> ExecStartPre=/usr/local/rvm/bin/rvm use %i
>> ExecStart=/${GEM_HOME}/bin/gem server --daemon --port 8808
>>
>> The rvm environment needs to be initialised (by running
>> /etc/profile.d/rvm.sh) and this needs to happen in a bash login shell (this
>> is due to the design of rvm).
>>
>> I think the ExecStart* lines in the above example are each invoked in a
>> separate environment (so the initialisation performed by the first is lost
>> before the second and third items are processed). Is this right or do I
>> misunderstand?
> That's right, but not because of systemd.
>
> When you run "bash /etc/profile.d/rvm.sh", it works in non-interactive
> mode: first it interprets the given script, then simply exits. This is
> the same regardless of where and how it is run. Since profile.d/rvm.sh
> just sets environment variables, and those do not propagate upwards,
> the entire command has no effect.
>
> In actual login sessions, your shell starts and "sources"
> /etc/profile, which then "sources" the profile.d scriptlets – instead
> of running a separate copy of bash for them. Since systemd is not a
> shell and does not understand (ba)sh syntax, the same thing cannot be
> done here, at least not directly.
yeah, I knew about /etc/profile being sourced and it sourcing the 
scripts in profile.d and that resulting in configuring a current shell 
environment. I had overlooked the fact that systemd isn't executing a 
shell environment.
>> My question is to ask how would I create a unit that starts a service in an
>> properly initialised environment when the only way to initialise that
>> environment is to run a bash setup script that requires it to be run in a
>> login shell ?
> My first thought is "fix the damn setup script". Surely rvm already
> has a way to be used non-interactively?...
>
> Actually – is the "login shell" requirement imposed by rvm.sh itself
> checking for that, or simply by the fact that rvm.sh is in
> /etc/profile.d? — If it's the former, then rvm is broken, but if it's
> the latter, then it's not a real requirement as rvm.sh could be
> sourced manually without relying on /etc/profile to do it.
The "login shell" requirement is imposed by rvm.sh but only because the 
normal way of running it is, as you say, to source it via /etc/profile. 
You can indeed directly source /etc/profile.d/rvm.sh.However, what it 
does is set up a shell function called "rvm" that is used by subsequent 
commands, so it all needs to happen in a single environment (my example 
unit above absolutely listed the path to 'rvm' but it must not do this, 
because 'rvm' should resolve to a shell function not to an executable. A 
command in systemd ExecStart must be given absolutely so that's break.


It might be that all you need is to set $PATH and $GEM_HOME
environment variables using the Environment= property (or
EnvironmentFile=.)

(But note that you cannot use variables in the zeroth argument for ExecStart.)

Ah yes, I just relaized that. That is another spanner because the path 
to ${GEM_HOME}/bin/gem is dependent on the rvm environment correctly 
setting up ${GEM_HOME}.
>> My solution that works is to use a unit to invoke a bash script that
>> performs the initialisation and then starts the service. But I feel this
>> somewhat negates the benefits of systemd not being based on shell scripts.
>> I'd like to try and get it to work with a unit file and no supporting
>> scripts, if this is possible.
> It doesn't completely negate the benefits, as the script only performs
> initialization for your service – you still get the advantages of
> systemd enforcing dependencies, starting multiple services in
> parallel, process tracking, and pretty much everything else. The only
> significant downsides I can think of are having to load heavy
> /bin/bash, and similarly heavy rvm.
>
> I use rbenv to manage different Ruby versions, and while it probably
> doesn't offer the same functionality as rvm, it's also much simpler to
> use: it only needs <rbenv-path>/shims to be added to $PATH.
I was going to look at rbenv a while back but I stuck with rvm because I 
like the way it can easliy build new environments. I think what I have 
learnt from this is that an rvm unit would need to set up a shell 
environment that included the 'rvm' function and then call that function 
to issue further commands. None of that is congruent with what systemd 
does (it isn't a shell environment and it can only invoke executables 
using an absolute path that cannot be specified using environment 
variables). I think, in this case, using a supporting shell script is 
the only way to go. My scripted solution works for me and I'm just gonna 
run with it. I was trying to be too much of a purist :)

John.
> --
> Mantas Mikulėnas <grawity at gmail.com>
>



More information about the systemd-devel mailing list