HenrikBengtsson / CBI-software

A Scientific Software Stack for HPC (CentOS oriented)
https://wynton.ucsf.edu/hpc/software/software-repositories.html
5 stars 2 forks source link

R: Detect when Conda is installed and active - if so, refuse to load the module #80

Closed HenrikBengtsson closed 1 year ago

HenrikBengtsson commented 1 year ago

Background

When Conda is installed, it is very++ likely that the user will run into all kind of compilation errors when they try to install R package.

Idea

Figure out how to detect when Conda is active from Lua. If detected, then the r module should produce something like:

$ module load CBI r
ERROR: Conda must not be active when using this module, because it will cause a lot of conflicts that are hard to troubleshoot. Please deactivate Conda first.
HenrikBengtsson commented 1 year ago

Checking for the existence of environment variable CONDA_EXE is probably a first clue. It's not sufficient, though, because it might be set without any conda environment being active. Maybe CONDA_DEFAULT_ENV can be used to decide if there's an active environment or not (including the 'base' environment)?

The goal here is not to be 100% bulletproof, but to at least catch the most common scenarios.

HenrikBengtsson commented 1 year ago

It looks like:

local conda_env = os.getenv("CONDA_DEFAULT_ENV")
if conda_env ~= nil then
  LmodError("Using the " .. "'" .. name .. "'" .. " module when a Conda environment is active risks resulting in hard-to-troubleshoot errors. Make sure to deactivate the Conda " .. "'" .. conda_env .. "'" .. " environment before loading this module.")
end

will do it.

HenrikBengtsson commented 1 year ago

A generalization of this would be to define a Lua function, e.g. in the CBI module:

-- Assert that there is no active Conda environment
assert_no_conda_environment = function()
  local conda_env = os.getenv("CONDA_DEFAULT_ENV")
  if conda_env ~= nil then
    LmodError("Using the " .. "'" .. myModuleName() .. "'" .. " module when a Conda environment is active risks resulting in hard-to-troubleshoot errors due to library conflicts. Make sure to deactivate the Conda " .. "'" .. conda_env .. "'" .. " environment before loading this module, e.g. 'conda deactivate'.")
  end
end

and then use

-- Protect against a conflicting Conda stack
assert_no_conda_environment()

in whatever module that needs to protect against it. Example of use:

$ module load r
Lmod has detected the following error: Using the 'r' module when a Conda
environment is active risks resulting in hard-to-troubleshoot errors due to
library conflicts. Make sure to deactivate the Conda 'base' environment before
loading this module, e.g. 'conda deactivate'. 
While processing the following module(s):
    Module fullname  Module Filename
    ---------------  ---------------
    r/trunk          /home/hb/modulefiles/r/trunk.lua
HenrikBengtsson commented 1 year ago

A version where the severity can be controlled by an environment variable CBI_ON_CONDA, where the default is to warn ("warning"). If set to "ignore", it is completely silent.

-- Assert that there is no active Conda environment
assert_no_conda_environment = function()  
  local conda_env = os.getenv("CONDA_DEFAULT_ENV")
  if conda_env ~= nil then
    local action = os.getenv("CBI_ON_CONDA") or "warning"
    if action ~= "ignore" then
      local notify
      if action == "warning" then
        notify = LmodWarning
      else
        notify = LmodError
      end
      notify("Using the " .. "'" .. myModuleName() .. "'" .. " module when a Conda environment is active risks resulting in hard-to-troubleshoot errors due to library conflicts. Make sure to deactivate the Conda " .. "'" .. conda_env .. "'" .. " environment before loading this module, e.g. 'conda deactivate'.")
    end
  end
end

This version will allow us to roll this out softly, i.e. start with a non-disruptive warning. Then, after a while, we can escalate it to "error" by default, while the use can down escalate if they really need to, e.g.

CBI_ON_CONDA=ignore module load CBI r
HenrikBengtsson commented 1 year ago

The same but without using notify; maybe easier to understand this way:

-- Assert that there is no active Conda environment
assert_no_conda_environment = function()  
  local conda_env = os.getenv("CONDA_DEFAULT_ENV")
  if conda_env ~= nil then
    local action = os.getenv("CBI_ON_CONDA") or "warning"
    local msg = "Using the " .. "'" .. myModuleName() .. "'" .. " module when a Conda environment is active risks resulting in hard-to-troubleshoot errors due to library conflicts. Make sure to deactivate the Conda " .. "'" .. conda_env .. "'" .. " environment before loading this module, e.g. 'conda deactivate'."
    if action == "error" then
      LmodError(msg)
    elseif action == "warning" then
      LmodWarning(msg)
    end
  end
end
HenrikBengtsson commented 1 year ago

Deployed the warning on C4;

[henrik@c4-dev1 r]$ conda activate base
(base) [henrik@c4-dev1 r]$ module load r
Lmod Warning:  Using the 'r' module when a Conda environment is active risks resulting in
hard-to-troubleshoot errors due to library conflicts. Make sure to deactivate the currently active Conda
'base' environment before loading this module, e.g. 'conda deactivate'. 
While processing the following module(s):
    Module fullname  Module Filename
    ---------------  ---------------
    r/4.2.2          /software/c4/cbi/modulefiles/r/4.2.2.lua

(base) [henrik@c4-dev1 r]$ conda deactivate
[henrik@c4-dev1 r]$ module load r
[henrik@c4-dev1 r]$ 

Let's see how it goes.

HenrikBengtsson commented 1 year ago

Deployed on wynton too