Configuring site-specific Lmod hooks¶
You may want to customize what happens when certain modules are loaded, for example, you may want to set additional environment variables. This is possible with LMOD hooks. A typical example would be when you want to tune the OpenMPI module for your system by setting additional environment variables when an OpenMPI module is loaded.
Location of the hooks¶
The EESSI software stack provides its own set of hooks in $LMOD_PACKAGE_PATH/SitePackage.lua
. This SitePackage.lua
also searches for site-specific hooks in two additional locations:
$EESSI_CVMFS_REPO/host_injections/$EESSI_VERSION/.lmod/SitePackage.lua
$EESSI_CVMFS_REPO/host_injections/$EESSI_VERSION/software/$EESSI_OS_TYPE/$EESSI_SOFTWARE_SUBDIR/.lmod/SitePackage.lua
The first allows for hooks that need to be executed for that system, irrespective of the CPU architecture. The second allows for hooks specific to a certain architecture.
Architecture-independent hooks¶
Hooks are written in Lua and can use any of the standard Lmod functionality as described in the Lmod documentation. While there are many types of hooks, you most likely want to specify a load or unload hook. Note that the EESSI hooks provide a nice example of what you can do with hooks. Here, as an example, we will define a load
hook that environment variable MY_ENV_VAR
to 1
whenever an OpenMPI
module is loaded.
First, you typically want to load the necessary Lua packages:
-- $EESSI_CVMFS_REPO/host_injections/$EESSI_VERSION/.lmod/SitePackage.lua
-- The Strict package checks for the use of undeclared variables:
require("strict")
-- Load the Lmod Hook package
local hook=require("Hook")
Next, we define a function that we want to use as a hook. Unfortunately, registering multiple hooks of the same type (e.g. multiple load
hooks) is only supported in Lmod 8.7.35+. EESSI version 2023.06 uses Lmod 8.7.30. Thus, we define our function without the local keyword, so that we can still add to it later in an architecture-specific hook (if we wanted to):
-- Define a function for the hook
-- Note that we define this without 'local' keyword
-- That way we can still add to this function in an architecture-specific hook
function set_my_env_var_openmpi(t)
local simpleName = string.match(t.modFullName, "(.-)/")
if simpleName == 'OpenMPI' then
setenv('MY_ENV_VAR', '1')
end
end
for the same reason that multiple hooks cannot be registered, we need to combine this function for our site-specific (architecture-independent) with the function that specifies the EESSI load
hook. Note that all EESSI hooks will be called eessi_<hook_type>_hook
by convention.
-- Registering multiple hook functions, e.g. multiple load hooks is only supported in Lmod 8.7.35+
-- EESSI version 2023.06 uses lmod 8.7.30. Thus, we first have to combine all functions into a single one,
-- before registering it as a hook
local function combined_load_hook(t)
-- Call the EESSI load hook (if it exists)
-- Note that if you wanted to overwrite the EESSI hooks (not recommended!), you would omit this
if eessi_load_hook ~= nil then
eessi_load_hook(t)
end
-- Call the site-specific load hook
set_my_env_var_openmpi(t)
end
Then, we can finally register this function as an Lmod hook:
Thus, our complete $EESSI_CVMFS_REPO/host_injections/$EESSI_VERSION/.lmod/SitePackage.lua
now looks like this (omitting the comments):
require("strict")
local hook=require("Hook")
function set_my_env_var_openmpi(t)
local simpleName = string.match(t.modFullName, "(.-)/")
if simpleName == 'OpenMPI' then
setenv('MY_ENV_VAR', '1')
end
end
local function combined_load_hook(t)
if eessi_load_hook ~= nil then
eessi_load_hook(t)
end
set_my_env_var_openmpi(t)
end
hook.register("load", combined_load_hook)
Note that for future EESSI versions, if they use Lmod 8.7.35+, this would be simplified to:
require("strict")
local hook=require("Hook")
local function set_my_env_var_openmpi(t)
local simpleName = string.match(t.modFullName, "(.-)/")
if simpleName == 'OpenMPI' then
setenv('MY_ENV_VAR', '1')
end
end
hook.register("load", set_my_env_var_openmpi, "append")
Architecture-dependent hooks¶
Now, assume that in addition we want to set an environment variable MY_SECOND_ENV_VAR
to 5
, but only for nodes that have the zen3
architecture. First, again, you typically want to load the necessary Lua packages:
-- $EESSI_CVMFS_REPO/host_injections/$EESSI_VERSION/software/linux/x86_64/amd/zen3/.lmod/SitePackage.lua
-- The Strict package checks for the use of undeclared variables:
require("strict")
-- Load the Lmod Hook package
local hook=require("Hook")
Next, we define the function for the hook itself
-- Define a function for the hook
-- This time, we can define it as a local function, as there are no hooks more specific than this
local function set_my_second_env_var_openmpi(t)
local simpleName = string.match(t.modFullName, "(.-)/")
if simpleName == 'OpenMPI' then
setenv('MY_SECOND_ENV_VAR', '5')
end
end
Then, we combine the functions into one
local function combined_load_hook(t)
-- Call the EESSI load hook first
if eessi_load_hook ~= nil then
eessi_load_hook(t)
end
-- Then call the architecture-independent load hook
if set_my_env_var_openmpi(t) ~= nil then
set_my_env_var_openmpi(t)
end
-- And finally the architecture-dependent load hook we just defined
set_my_second_env_var_openmpi(t)
end
before finally registering it as an Lmod hook
Thus, our full $EESSI_CVMFS_REPO/host_injections/$EESSI_VERSION/software/linux/x86_64/amd/zen3/.lmod/SitePackage.lua
now looks like this (omitting the comments):
require("strict")
local hook=require("Hook")
local function set_my_second_env_var_openmpi(t)
local simpleName = string.match(t.modFullName, "(.-)/")
if simpleName == 'OpenMPI' then
setenv('MY_SECOND_ENV_VAR', '5')
end
end
local function combined_load_hook(t)
if eessi_load_hook ~= nil then
eessi_load_hook(t)
end
if set_my_env_var_openmpi(t) ~= nil then
set_my_env_var_openmpi(t)
end
set_my_second_env_var_openmpi(t)
end
hook.register("load", combined_load_hook)
Again, note that for future EESSI versions, if they use Lmod 8.7.35+, this would simplify to