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

Env mod 4 #7536

Closed
wants to merge 28 commits into from
Closed

Env mod 4 #7536

wants to merge 28 commits into from

Conversation

mgsternberg
Copy link
Contributor

@mgsternberg mgsternberg commented Mar 20, 2018

Introduction

This PR provides fixes for Spack to function with Environment Modules 4.x and to address minor coding issues.

I factored out the main fix addressed here from #7469. As mentioned in that PR in general, the issue is fundamental and would render Spack a non-starter for new users on a similar platform.

Issues and Fixes

  • Spack threw UnboundLocalError when using Environment Modules 4.x.

    • Solution: Add a continue statement in lib/spack/spack/environment.py:from_sourcing_file().

    This is the absolute minimum needed to accommodate Env-Mod-4.x. It turns out that a changed content of BASH_FUNC_module() triggered this problem (see next point).

  • BASH_FUNC_module() and ENV must be blacklisted to not show up in generated modulefiles.

    • Root cause: Env-Mod-4 initializes module() differently, depending on the tty being interactive or not, or more specifically, where stderr goes (see reason in code):
    $ env - bash -l -c 'env' | grep 'module()'
    BASH_FUNC_module()=() {  _moduleraw $* 2>&1
    $ env - bash -l -c 'env' 2> /dev/null | grep 'module()'
    BASH_FUNC_module()=() {  if [ "$MODULES_SILENT_SHELL_DEBUG" = '1' ]; then

    and:

    $ ( env;  env - bash -l -c 'env' ) | grep ^ENV
    ENV=/home/username/.bashrc
    ENV=/usr/share/Modules/init/profile.sh

    Blacklisting BASH_FUNC_module() happens to sidestep the initial problem, but the latter should still be fixed to address the uninitialized variable issue.

  • A TypeError/NoneType was thrown if blacklist was in the YAML config but had all entries commented out (as happened during debugging), or equivalently has no entries.

    • Solution: Extend a relevant if clause.

Background

The Environment Modules software project recently saw some major changes when Xavier Delaruelle xavier.delaruelle@cea.fr took on maintanence. He froze the former C-based implementation at 3.x, since it had become difficult to maintain and extend, and instead made the formerly alternative Tcl implemention the primary engine. Like Modules-C, the Modules-Tcl goes back quite some time and was mature but nonetheless new and interesting features are available with 4.x.

Pre-release versions of Environment Modules-4, like Modules-Tcl previously, did not work at all with Spack for their lack of a modulecmd script/executable. The 4.x release version conveniently added such a script, which Spack can latch on to. For end users, more involved interfaces are available in a module function for Bash and numerous scripting languages, including Python. Those front-end functions support the concept of quarantining variables, in particular LD_LIBRARY_PATH, which is needed to ensure that any user-side environment modifications do not interfere with running the Tcl interpreter for the Modules engine itself. Since Spack itself isolates module commands, however, this quarantine may not strictly be needed.

Development note

While implementing the above, I got the impression that lib/spack/spack/environment.py:from_sourcing_file() looks somewhat, shall we say, "organically grown", which is concerning given the complexity of its task. That function could benefit from being split into two tasks:

  1. sourcing a file and reading the resulting environment, and
  2. comparing two environments stored as dict objects.

Factoring out task 2 should make it rather more easy to test. It could be done here or in a separate PR. Of interest might be createmodule.py (it is under GPLv2). It uses a slightly different algorithm, jumping off with the rather nifty construct (prepend,append) = env2[key].split(env1[key]). There is also a Bash-based version which, remarkably, is shorter.

mgsternberg added a commit to mgsternberg/spack that referenced this pull request Mar 20, 2018
@mgsternberg
Copy link
Contributor Author

Oh my – having factored out this PR from #7469, I realized there that blacklist in lib/spack/spack/environment.py:from_sourcing_file() is wholly unrelated to the one or more module-flavor-specific environment_blacklist entries in modules.yaml 🤦‍♂️.

This decouples the issues above from one another, but doesn't change their impact, in particular for the primary one.

@mgsternberg mgsternberg mentioned this pull request Jun 14, 2018
@tgamblin tgamblin added this to To do in Modules Improvement Jul 6, 2018
@mgsternberg
Copy link
Contributor Author

I rolled back the change to lib/spack/spack/util/module_cmd.py as it won't be relevant anymore once #8570 is merged.

The other changes are still very much needed to fix bugs in environment_modifications() and from_sourcing_file(), as well as to accommodate Environment Modules 4.x as described in the Intro.

Copy link
Member

@alalazo alalazo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically LGTM. Can you add some tests that stress the lines you changed or added?

# distinct from "environment_blacklist" in modules.yaml, which is
# applied on OUTPUT to a specific module flavor.
# ---------------------------------------------------------------------
blacklist.extend(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the name seems confusing, what do you think of renaming blacklist and whitelist to something that conveys better their role in this function and remove the comment above?

On a side not: I also slightly prefer to construct a list explicitly rather than splitting a string, given that we have items in it like _.

@alalazo alalazo moved this from Needs review to In progress in Modules Improvement Sep 7, 2018
@xdelaruelle
Copy link
Contributor

@mgsternberg @alalazo it would be great to have this PR merged to enable the use of new Modules releases (4+). What can be done to help ?

@alalazo
Copy link
Member

alalazo commented Nov 14, 2018

@xdelaruelle As far as I am concerned a rebase + unit tests + reply to the few minor comments above would do.

@alalazo
Copy link
Member

alalazo commented Feb 28, 2019

Looking at the issues reported here. Concerning:

A TypeError/NoneType was thrown if blacklist was in the YAML config but had all entries commented out (as happened during debugging), or equivalently has no entries.

This is what Spack at 617c1a3 reports:

$ spack config blame modules
==> Error: /home/mculpo/PycharmProjects/spack/etc/spack/modules.yaml:3: None is not of type 'array'

so it doesn't seem to be an issue anymore.

@alalazo
Copy link
Member

alalazo commented Feb 28, 2019

Spack threw UnboundLocalError when using Environment Modules 4.x.

BASH_FUNC_module() and ENV must be blacklisted to not show up in generated modulefiles.

I also can't reproduce the two bugs above using 617c1a3 with the intel module and environment-modules@4.2.2

alalazo added a commit to epfl-scitas/spack that referenced this pull request Feb 28, 2019
closes spack#7536

Credits for this change goes to @mgsternberg (original author of spack#7536)

The new variables being ignored are specific to Modules v4.
@mgsternberg
Copy link
Contributor Author

mgsternberg commented Mar 1, 2019

@alalazo wrote:

A TypeError/NoneType was thrown if blacklist was in the YAML config but had all entries commented out (as happened during debugging), or equivalently has no entries.

This is what Spack at 617c1a3 reports:

$ spack config blame modules
==> Error: /home/mculpo/PycharmProjects/spack/etc/spack/modules.yaml:3: None is not of type 'array'

so it doesn't seem to be an issue anymore.

It's not a showstopper anymore but the error message is terrible. It uses Python lingo for a YAML file and therefore looks rather like a bug.

Example

The following is valid YAML (so says yamllint 1.15) and Spack clearly parses the syntax just fine but it stumbles on its own schema:

modules:
  tcl:
    all:
      filter:
        environment_blacklist:
          # foo
$ spack config blame modules
==> Error: /home/stern/.spack/modules.yaml:5: None is not of type 'array'

That error message would be far better for the user if it expressed that an empty YAML sequence (array) is disallowed by the Spack schema.

But, not only does that seem overly harsh, you can't intuitively comment out the key of the sequence, because the trouble applies to the parent YAML mapping (dict) as well:

modules:
  tcl:
    all:
      filter:
#        environment_blacklist:
#          # foo
$ spack config blame modules
==> Error: /home/stern/.spack/modules.yaml:4: None is not of type 'object'

Moreover, the trouble recursively climbs up the hierarchy:

modules:
#  tcl:
#    all:
#      filter:
#        environment_blacklist:
#          # foo
$ spack config blame modules
==> Error: /home/stern/.spack/modules.yaml:1: None is not of type 'object'

Suggestion

Permit (tolerate) empty YAML sequences and mappings in Spack config files.

Is this something worthy of discussing further?

alalazo added a commit to epfl-scitas/spack that referenced this pull request Mar 4, 2019
closes spack#7536

Credits for this change goes to @mgsternberg (original author of spack#7536)

The new variables being ignored are specific to Modules v4.
alalazo added a commit to epfl-scitas/spack that referenced this pull request Mar 13, 2019
closes spack#7536

Credits for this change goes to @mgsternberg (original author of spack#7536)

The new variables being ignored are specific to Modules v4.
alalazo pushed a commit that referenced this pull request Mar 21, 2019
alalazo added a commit to epfl-scitas/spack that referenced this pull request Mar 21, 2019
closes spack#7536

Credits for this change goes to @mgsternberg (original author of spack#7536)

The new variables being ignored are specific to Modules v4.
alalazo added a commit to epfl-scitas/spack that referenced this pull request May 23, 2019
closes spack#7536

Credits for this change goes to @mgsternberg (original author of spack#7536)

The new variables being ignored are specific to Modules v4.
alalazo added a commit to epfl-scitas/spack that referenced this pull request Jul 3, 2019
closes spack#7536

Credits for this change goes to @mgsternberg (original author of spack#7536)

The new variables being ignored are specific to Modules v4.
alalazo added a commit to epfl-scitas/spack that referenced this pull request Jul 9, 2019
closes spack#7536

Credits for this change goes to @mgsternberg (original author of spack#7536)

The new variables being ignored are specific to Modules v4.
Modules Improvement automation moved this from In progress to Done Jul 16, 2019
becker33 pushed a commit that referenced this pull request Jul 16, 2019
* from_sourcing_file: fixed a bug + added a few ignored variables

closes #7536

Credits for this change goes to mgsternberg (original author of #7536)

The new variables being ignored are specific to Modules v4.

* Use Spack Executable in 'EnvironmentModifications.from_sourcing_file'

Using this class avoids duplicating lower level logic to decode
stdout and handle non-zero return codes

* Extracted a function that returns the environment after sourcing files

The logic in `EnvironmentModifications.from_sourcing_file` has been
simplified by extracting a function that returns a dictionary with the
environment one would have after sourcing the files passed as argument.

* Further refactoring of EnvironmentModifications.from_sourcing_file

Extracted a function that sanitizes a dictionary removing keys that are
blacklisted, but keeping those that are whitelisted. Blacklisting and
whitelisting can be done on literals or regex.

Extracted a new factory that creates an instance of
EnvironmentModifications from a diff of two environments.

* Added unit tests

* PS1 is blacklisted + more readable names for some variables
dev-zero pushed a commit to dev-zero/spack that referenced this pull request Aug 13, 2019
…k#10753)

* from_sourcing_file: fixed a bug + added a few ignored variables

closes spack#7536

Credits for this change goes to mgsternberg (original author of spack#7536)

The new variables being ignored are specific to Modules v4.

* Use Spack Executable in 'EnvironmentModifications.from_sourcing_file'

Using this class avoids duplicating lower level logic to decode
stdout and handle non-zero return codes

* Extracted a function that returns the environment after sourcing files

The logic in `EnvironmentModifications.from_sourcing_file` has been
simplified by extracting a function that returns a dictionary with the
environment one would have after sourcing the files passed as argument.

* Further refactoring of EnvironmentModifications.from_sourcing_file

Extracted a function that sanitizes a dictionary removing keys that are
blacklisted, but keeping those that are whitelisted. Blacklisting and
whitelisting can be done on literals or regex.

Extracted a new factory that creates an instance of
EnvironmentModifications from a diff of two environments.

* Added unit tests

* PS1 is blacklisted + more readable names for some variables
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
No open projects
Development

Successfully merging this pull request may close these issues.

None yet

4 participants