This service will be undergoing maintenance at 00:00 UTC, 2017-10-23 It is expected to last about 30 minutes
Bug 1016962 - scl enable does not set up the environment in a nested invocation
scl enable does not set up the environment in a nested invocation
Status: CLOSED WONTFIX
Product: Red Hat Enterprise Linux 6
Classification: Red Hat
Component: scl-utils (Show other bugs)
6.4
Unspecified Unspecified
unspecified Severity unspecified
: rc
: ---
Assigned To: Jan Zeleny
BaseOS QE - Apps
:
Depends On:
Blocks:
  Show dependency treegraph
 
Reported: 2013-10-09 00:26 EDT by Miciah Dashiel Butler Masters
Modified: 2013-10-16 07:47 EDT (History)
1 user (show)

See Also:
Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed: 2013-10-09 02:54:37 EDT
Type: Bug
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---


Attachments (Terms of Use)

  None (edit)
Description Miciah Dashiel Butler Masters 2013-10-09 00:26:37 EDT
Description of problem:

If I run `scl enable foo bar` where bar runs `scl enable foo baz`, the latter scl enable command does not set up the environment for the foo collection.


Version-Release number of selected component (if applicable):

scl-utils-20120927-2.el6_4.6.x86_64


How reproducible:

Thoroughly.


Steps to Reproduce:

1. PATH=/bin:/usr/bin LD_LIBRARY_PATH= MANPATH= scl enable ruby193 'PATH=/bin:/usr/bin LD_LIBRARY_PATH= MANPATH= scl enable ruby193 '\''echo $PATH ; echo $LD_LIBRARY_PATH ; echo $MANPATH'\'


Actual results:

The inner scl enable command does not change the values for the PATH, LD_LIBRARY_PATH, and MANPATH environment variables:

    # PATH=/bin:/usr/bin LD_LIBRARY_PATH= MANPATH= scl enable ruby193 'PATH=/bin:/usr/bin LD_LIBRARY_PATH= MANPATH= scl enable ruby193 '\''echo $PATH ; echo $LD_LIBRARY_PATH ; echo $MANPATH'\'
    /bin:/usr/bin
    
    
    #

Expected results:

The inner scl enable command should set the values for the PATH, LD_LIBRARY_PATH, and MANPATH environment variables appropriate for the collection:

    # PATH=/bin:/usr/bin LD_LIBRARY_PATH= MANPATH= scl enable ruby193 'PATH=/bin:/usr/bin LD_LIBRARY_PATH= MANPATH= scl enable ruby193 '\''echo $PATH ; echo $LD_LIBRARY_PATH ; echo $MANPATH'\'
    /opt/rh/ruby193/root/usr/bin:/bin:/usr/bin
    /opt/rh/ruby193/root/usr/lib64
    /opt/rh/ruby193/root/usr/share/man:

Additional info:

The problem is that scl enable sets the X_SCLS environment variable and does not set the environment up if the collection is already listed in X_SCLS:

    # export PATH=/bin:/usr/bin LD_LIBRARY_PATH= MANPATH=
    # X_SCLS=' ' scl enable ruby193 'echo $PATH ; echo $LD_LIBRARY_PATH ; echo $MANPATH'
    /opt/rh/ruby193/root/usr/bin:/bin:/usr/bin
    /opt/rh/ruby193/root/usr/lib64
    /opt/rh/ruby193/root/usr/share/man:
    # X_SCLS='ruby193 ' scl enable ruby193 'echo $PATH ; echo $LD_LIBRARY_PATH ; echo $MANPATH'
    /bin:/usr/bin
    
    
    #

This is unexpected and undocumented behaviour:

    # man scl |grep X_SCLS
    #

In the context in which we encountered this problem, we use a wrapper script for Ruby that essentially runs scl enable ruby193 "$@".  We use this wrapper script in the shebang of our Ruby scripts to ensure that they run in the environment of the ruby193 software collection.  We have one such script that runs some scripts that munge the path and then runs another script with our wrapper in its shebang.  When this last script ran, the wrapper script failed to override the munged PATH setting because the first script had already set X_SCLS='ruby193 '.

Here is a minimal set of scripts to illustrate the general setup described in the preceding paragraph:

    # cat /bin/ruby-wrapper
    #!/bin/sh
    scl enable ruby193 "ruby $*"
    # cat /bin/a
    #!/bin/ruby-wrapper
    puts `/bin/b`
    # cat /bin/b
    #!/bin/sh
    export PATH=/bin:/usr/bin
    /bin/c
    # cat /bin/c
    #!/bin/ruby-wrapper
    puts RUBY_VERSION
    # /bin/a
    1.8.7
    #

/bin/ruby-wrapper is used a shebang that ensures that the Ruby interpreter from the ruby193 is used.  Scripts /bin/a and /bin/c use it.  /bin/a calls /bin/b, which munges the path and then calls /bin/c.  Because X_SCLS is already set to 'ruby193 ' when /bin/c runs, /bin/ruby-wrapper fails to set PATH, and so /bin/c runs with the wrong Ruby interpreter.
Comment 2 Jan Zeleny 2013-10-09 02:54:37 EDT
This was never supposed to work. I'm planning to include scl_source script that will handle the functionality a bit differently, take a look at bug 874417.
Comment 3 Miciah Dashiel Butler Masters 2013-10-09 10:48:26 EDT
Should I file a new bug report regarding the manpage? X_SCLS is not documented, the behaviour with nested scl enable invocations is not documented, and this behaviour (and change in behaviour) caught us by surprise.

By the way, I am told the behaviour changed between scl-utils-20120927-2.el6.x86_64 (where scl enable behaved as expected and set PATH in nested invocations) and scl-utils-20120927-2.el6_4.6.x86_64 (where I see the problem I described in the initial report).
Comment 4 Jan Zeleny 2013-10-09 11:00:26 EDT
(In reply to Miciah Dashiel Butler Masters from comment #3)
> Should I file a new bug report regarding the manpage? X_SCLS is not
> documented, the behaviour with nested scl enable invocations is not
> documented, and this behaviour (and change in behaviour) caught us by
> surprise.

Could I ask what manpage do you have in mind? Scl's man page is intended for users, not for collection maintainers.

Regarding your next comments:
- X_SCLS is an internal of scl-utils, that will not be documented anywhere
- nested scl invocations are possible but the nesting needs to be done in the "command" you execute, not in the scriptlet. SCL starts a subshell so any nesting you make will be lost after the subshell exists. IIRC this is well documented in Software Collections Guide, which is the right place.
- forgive me for being blunt but if you depended on a bug in scl-utils (see below), it's not my fault that the bugfix caught you by surprise

> By the way, I am told the behaviour changed between
> scl-utils-20120927-2.el6.x86_64 (where scl enable behaved as expected and
> set PATH in nested invocations) and scl-utils-20120927-2.el6_4.6.x86_64
> (where I see the problem I described in the initial report).

The behavior did not change. The only change related to this was that enabling one collection multiple times doesn't work anymore. But considering that it was never meant to work, it is not a behavior change, it is a bugfix.
Comment 5 Miciah Dashiel Butler Masters 2013-10-09 11:19:15 EDT
I read scl's manpage as a user, and that is where I would expect to see a caveat about nested invocations.  I use the ruby193 collection; I do not maintain it.

I do not understand the distinction from what I am doing when you say that "the nesting needs to be done in the 'command' you execute, not in the scriptlet." As I understand it, the nesting _is_ occurring in the command I execute.

To go over what happens,

1. when I run /bin/a, its shebang causes the operating system to run /bin/ruby-wrapper /bin/a, which runs scl enable ruby193 'ruby /bin/a', which forks a new ruby process;

2. this new ruby process for /bin/a runs /bin/b;

3. when /bin/a runs /bin/b, it forks a new shell process;

4. this new shell process for /bin/b runs /bin/c;

5. when /bin/b runs /bin/c, the shebang for /bin/c has a shebang that causes the operating system to run /bin/ruby-wrapper /bin/c, which runs scl enable ruby193 'ruby /bin/c'.

I am referring to the execution of scl enable ruby193 'ruby /bin/c' in Step 5 as a nested invocation of scl enable ruby193 because it was done in a process that forked from a process (in Step 3) that was forked from a process (in Step 1) that invoked scl enable ruby193.  I have may have simplified the details, but it seems clear to me that the nesting is being done in the command that I execute.  I am not modifying any scl scriptlets anywhere.
Comment 6 Jan Zeleny 2013-10-11 03:53:19 EDT
(In reply to Miciah Dashiel Butler Masters from comment #5)
> I read scl's manpage as a user, and that is where I would expect to see a
> caveat about nested invocations.  I use the ruby193 collection; I do not
> maintain it.

As a user you shouldn't have any clue that there is some nested invocation going on. If you do, than that's probably maintainer's fault and I suggest talking to the maintainer of the collection in question.


> I do not understand the distinction from what I am doing when you say that
> "the nesting needs to be done in the 'command' you execute, not in the
> scriptlet." As I understand it, the nesting _is_ occurring in the command I
> execute.

My example was:
bash$ scl enable ruby193 bash
bash_2$ scl enable python27 bash
bash_3$ # now you have python27 and ruby193 enabled


Now this gets a bit tricky, I'm a bit confused by your description, so let's try to make it a bit clear:

> 1. when I run /bin/a, its shebang causes the operating system to run
> /bin/ruby-wrapper /bin/a, which runs scl enable ruby193 'ruby /bin/a', which
> forks a new ruby process;

So step 1 is simply to run "scl enable ruby193 /bin/some_script", right?

> 2. this new ruby process for /bin/a runs /bin/b;
> 3. when /bin/a runs /bin/b, it forks a new shell process;
> 4. this new shell process for /bin/b runs /bin/c;

Ok

> 5. when /bin/b runs /bin/c, the shebang for /bin/c has a shebang that causes
> the operating system to run /bin/ruby-wrapper /bin/c, which runs scl enable
> ruby193 'ruby /bin/c'.

This is a part that I'm confused about. Sounds like /bin/c is recursively executing itself but I'm probably (hopefully) mistaken.

> I am referring to the execution of scl enable ruby193 'ruby /bin/c' in Step
> 5 as a nested invocation of scl enable ruby193 because it was done in a
> process that forked from a process (in Step 3) that was forked from a
> process (in Step 1) that invoked scl enable ruby193.  I have may have
> simplified the details, but it seems clear to me that the nesting is being
> done in the command that I execute.  I am not modifying any scl scriptlets
> anywhere.

Well, this should work *in general* but there are some exceptions. It is for example possible the one of the processes on the way doesn't preserve the environment and tries to compensate for that by enabling one collection twice which is forbidden. Try to communicate that with the maintainer of the collection.

In any case, I still don't see the need to mention the recursive enabling of collections in the man page, it's something that users really shouldn't know about and won't know about if collections built on scl-utils work properly.
Comment 7 Miciah Dashiel Butler Masters 2013-10-11 14:46:52 EDT
I had not seen that example before.  Where does it come from? I do not see it in your earlier comments to this bug report, in the Release Notes[1], or in the manpage for scl, and I am not aware of any other documentation (there is no other official documentation in the scl-utils RPM or on access.redhat.com).

1. https://access.redhat.com/site/documentation/en-US/Red_Hat_Software_Collections/1/html-single/1.0_Release_Notes/index.html

Expanding on your example, the following illustrates the essence of what we are trying to do:

    $ ruby -v
    ruby 1.8.7 (2011-06-30 patchlevel 352) [x86_64-linux]
    $ scl enable ruby193 bash
    $ ruby -v
    ruby 1.9.3p327 (2012-11-10 revision 37606) [x86_64-linux]
    $ PATH=/usr/bin:/bin
    $ scl enable ruby193 bash
    $ ruby -v
    ruby 1.8.7 (2011-06-30 patchlevel 352) [x86_64-linux]
    $

The above example is silly, so I gave a more realistic example based on real-world usage of Software Collections in a product that we ship where we want the Ruby 1.9.3 interpreter and use a wrapper that scripts can use instead of /usr/bin/ruby (which will be the Ruby 1.8.7 interpreter on RHEL6) in order to enable the ruby193 software collection on RHEL systems in order to ensure that scripts that use that wrapper run with the Ruby 1.9.3 interpreter.  (On Fedora systems, where Ruby 1.9.3 is the default Ruby interpreter, the wrapper is essentially a no-op.)

In your most recent comment regarding our scenario, you speculate that "one of the processes on the way doesn't preserve the environment and tries to compensate for that by enabling one collection twice which is forbidden," and that is exactly is happening.  I now understand where our expectations of scl enable differ from the intentions for its usage, and that it is improper usage of scl enable to use it in a wrapper script for shebangs.  Based on what you are saying now, it seems that we should be using something other than scl enable in our wrapper script.  Perhaps we must hardcode the PATH and LD_LIBRARY_PATH settings in the wrapper script.  If you can suggest a better approach, please let us know! In any case, thank you for explaining what is permissible usage of scl enable!

I'm still not satisfied regarding the documentation.  Your statements that "enabling one collection twice [...] is forbidden" and that you "still don't see the need to mention the recursive enabling of collections in the man page, it's something that users really shouldn't know about" are confusing.  In what sense is enabling one collection twice "forbidden" if the documentation doesn't even mention it?

Furthermore, Software Collections (in particular the scl-utils RPM) ships this nifty tool called "scl" that looked to us like the appropriate tool to use.  In scl-utils-20120927-2.el6.x86_64, scl enable did what we wanted when we told it to enable a collection that had previously been enabled in the same environment.  In scl-utils-20120927-2.el6_4.6.x86_64, scl enable did something else.  (I called this a change in behaviour; you say it is not a change in behaviour and call it a bug fix.) If the documentation had explained what the tool was supposed to do and how it could be used, we might have saved a lot of our time debugging the problem in our wrapper, and we would have saved you the time of dealing with this bug report—and it might save you time in the future by decreasing the probability of people similarly misusing scl enable in the future.  As it is, scl-utils includes a tool that looks like what we want, but isn't.  I'm suggesting that a little more documentation on how scl enable behaves and is intended to be used would have saved us all a lot of time.  We would have known that scl enable was not useful to us.  As it is, it's worth than useless.

By the way, although you said earlier that "X_SCLS is an internal of scl-utils, that will not be documented anywhere," I _did_ find one mention of X_SCLS in the Release Notes[2] when I scanned through it again today:

    The list of Software Collections that are enabled in the current session is stored in the $X_SCLS environment variable, for instance:

    ~]$ echo $X_SCLS
    python27 postgresql92

2. https://access.redhat.com/site/documentation/en-US/Red_Hat_Software_Collections/1/html-single/1.0_Release_Notes/index.html#sect-Installation_and_Usage-Use-Session

Presumably you will want to remove that information from the the documentation (the Release Notes document is the only documentation for Software Collections on access.redhat.com).

Thanks for your time!
Comment 8 Miciah Dashiel Butler Masters 2013-10-11 14:50:02 EDT
s/worth/worse/
Comment 9 Jan Zeleny 2013-10-16 07:47:52 EDT
>     $ ruby -v
>     ruby 1.8.7 (2011-06-30 patchlevel 352) [x86_64-linux]
>     $ scl enable ruby193 bash
>     $ ruby -v
>     ruby 1.9.3p327 (2012-11-10 revision 37606) [x86_64-linux]
>     $ PATH=/usr/bin:/bin
>     $ scl enable ruby193 bash
>     $ ruby -v
>     ruby 1.8.7 (2011-06-30 patchlevel 352) [x86_64-linux]

There is your problem. You are destroying the environment by setting different PATH that scl set before. This kind of tampering with the environment is not anticipated by scl-utils and is also *not* supposed to happen in collection-based packages.

-- snip --

> I'm still not satisfied regarding the documentation.  Your statements that
> "enabling one collection twice [...] is forbidden" and that you "still don't
> see the need to mention the recursive enabling of collections in the man
> page, it's something that users really shouldn't know about" are confusing. 
> In what sense is enabling one collection twice "forbidden" if the
> documentation doesn't even mention it?

Fair enough. But that's SCL maintainers' documentation you are talking about. Feel free to file a bug against that, that's a proper place where this should indeed be mentioned.

> Furthermore, Software Collections (in particular the scl-utils RPM) ships
> this nifty tool called "scl" that looked to us like the appropriate tool to
> use.  In scl-utils-20120927-2.el6.x86_64, scl enable did what we wanted when
> we told it to enable a collection that had previously been enabled in the
> same environment.  In scl-utils-20120927-2.el6_4.6.x86_64, scl enable did
> something else.  (I called this a change in behaviour; you say it is not a
> change in behaviour and call it a bug fix.) If the documentation had
> explained what the tool was supposed to do and how it could be used, we
> might have saved a lot of our time debugging the problem in our wrapper, and
> we would have saved you the time of dealing with this bug report—and it
> might save you time in the future by decreasing the probability of people
> similarly misusing scl enable in the future.

I definitely agree. Again, the maintainers' documentation is a proper place where this should be documented.

-- snip --

> We would have known that scl enable
> was not useful to us.  As it is, it's worth than useless.

That's where you are wrong. It may be useless to your very specific use case but in general it works for most people. If you need a different tool, feel free to drop me an email with specification of what you need and I'll see what I can do about it.

> By the way, although you said earlier that "X_SCLS is an internal of
> scl-utils, that will not be documented anywhere," I _did_ find one mention
> of X_SCLS in the Release Notes[2] when I scanned through it again today:

Fair enough. Not my idea to put it there though, probably someone from documentation team. I still stand by my previous statement that it is an internal and should be treated that way. I'm not sure if it can be removed from the release notes at this point though.

Note You need to log in before you can comment on or make changes to this bug.