Sticky modules

When providing a configurable environment to users, site's staff may require that some part of this environment remain loaded whatever the user does.

Such feature is for instance useful when every details of the user environment are configured through the use of modulefiles. Even the core setup that is usually configured through the /etc/profile.d initialization scripts. But by using modulefiles for core initialization, end users can fully see how things are setup on their environment by using module display. When the environment core setup is achieved by loading a specific modulefile, it is important that such module remains loaded to keep this initial setup on whatever the module actions the user performs over its environment.

This recipe describes how to keep modulefiles loaded by forbidding their unload. Such unloadable modules are called sticky modules.

Implementation

Sticky modules are simply modules that cannot be unloaded once loaded. Such behavior could be achieved by basically breaking the modulefile evaluation when attempting to unload the sticky module:

if {[module-info mode unload]} {
    break
}

Using the break Tcl command to stop the modulefile evaluation does not require to install a recent version of Modules to get a basic sticky mechanism.

To get a smoother sticky mechanism with two different level of stickiness, allowing to reload environment or to swap a sticky module by another version of the same module name, the sticky and super-sticky module tags have been introduced in Modules v4.7.

A modulefile is declared sticky by applying it the sticky tag with the module-tag modulefile command. Such sticky module cannot be unloaded, unless if the unload action is forced or if the module reloads after being unloaded.

Modulefile can also be defined super-sticky by applying the corresponding module tag. Super-sticky module cannot be unloaded even if the unload action is forced. It can only be unloaded if the module reloads afterward.

In case the stickiness applies to the generic module name (and does not target a specific module version or version-set), one version of the sticky or super-sticky module can be swapped by another version of this same module.

Compatible with Modules v4.7+

Usage examples

For this recipe, a core module acts as the initial setup of user's environment. This module must not be unloaded otherwise user's environment may be considered broken.

So this core module is tagged super-sticky with the module-tag modulefile command in core/.modulerc file:

module-tag super-sticky core

Once module got loaded, it cannot be unloaded even if these unload actions are forced.

$ module list
Currently Loaded Modulefiles:
 1) core/1.0

Key:
super-sticky
$ module unload core
Unloading core/1.0
  ERROR: Unload of super-sticky module 'core/1.0' skipped
$ module purge -f
Unloading core/1.0
  ERROR: Unload of super-sticky module 'core/1.0' skipped
$ module list
Currently Loaded Modulefiles:
 1) core/1.0

Key:
super-sticky

However it is still possible to change version of this super-sticky module.

$ module switch core/2.0
$ module list
Currently Loaded Modulefiles:
 1) core/2.0

Key:
super-sticky

In this recipe environment, the compiler module provides several flavors: compA and compB. Site's staff have decided that user's environment should always have a compiler module loaded by default.

So the compiler module is set sticky with the module-tag modulefile command in compiler/.modulerc file:

module-tag sticky compiler

As stickiness is defined over the generic compiler name, users can switch between available compiler flavors:

$ module list
Currently Loaded Modulefiles:
 1) core/2.0   2) compiler/compB/2.1

Key:
super-sticky  sticky
$ module switch compiler/compA
$ module list
Currently Loaded Modulefiles:
 1) core/2.0   2) compiler/compA/1.2

Key:
super-sticky  sticky

Unload attempt fails by default:

$ module unload compiler
Unloading compiler/compA/1.2
  ERROR: Unload of sticky module 'compiler/compA/1.2' skipped

However if a user really wants to get rid of the compiler module, the unload action can be forced:

$ module unload -f compiler
Unloading compiler/compA/1.2
  WARNING: Unload of sticky module 'compiler/compA/1.2' forced
$ module list
Currently Loaded Modulefiles:
 1) core/2.0

Key:
super-sticky

Last but not least, the sticky modules should get loaded when the user's shell session initializes. So the core and compiler modules should be defined for load in the initialization RC file /etc/environment-modules/initrc:

#%Module
module use --append .../example/sticky-modules/modulefiles
module load core
module load compiler/compB