Files
2026-09-28 17:14:01 +02:00

6.5 KiB

PModules

!!! warning Although this guide shows how to configure PModules on RHEL9, PModules with AFS backend is not supported on RHEL9!

This guide describes how to configure PModules on RHEL9 via hiera. More details about Pmodules can be found here: https://gitea.psi.ch/Pmodules/

PModules on RHEL9 (and central distribution of PModules) are currently not supported by the Linux team. Use at your own risk!

Installation packages (the PModules packages are available in the pli-misc repository - https://repos.psi.ch/rhel9/latest/pli-misc/):

base::pkg_group::pmodules:
  - "Pmodules"
# RHEL8 apparently requires that you explicitly specify the package version like this
#   - "Pmodules-2.0.2-1.el8"
#   - "Pmodules_bash-5.2.37-1.el8"
#   - "Pmodules_modules-3.2.10.2-1.el8"
base::package_groups:
  - "pmodules" 

Configuration of PModules via /etc/Pmodules.yaml and /etc/profile.d/pmodules.sh:

files::files:
  '/etc/Pmodules.yaml':
    content: |
      DefaultGroups: Tools:Programming
      DefaultReleaseStages: stable
      TmpDir: /var/tmp/
      DistfilesDir: /var/cache/Pmodules/distfiles
      Overlays:
      base:
          install_root: /opt/psi
  /etc/profile.d/pmodules.sh:
    content: |
      # source (p)module command
      if [[ ${UID} -ge 1000 && ! ${USER} =~ -adm$ ]]; then
        if [[ -r source /usr/share/Pmodules/init/bash ]]; then
          source /usr/share/Pmodules/init/bash
        fi
      fi

If you are using an NFS share to provide pmodules you should mount the share with local caching enabled for better performance (for more details see https://linux.psi.ch/documentation/admin-guide/configuration/files/mount#caching).

mounter::def::pmodules:
  ensure: 'mounted'
  mountpoint: '/opt/psi'
  device: 'whatever-server.psi.ch:/pmodules'
  options: 'fsc,nosharecache,sec=krb5'
  type: 'nfs4'

mounter::mounts:
  - 'pmodules'

Migration

!!! note These instructions were kindly provided by Ivano Talamo, and are based on the experience of migrating PModules for the RA cluster. There are no guarantees that this will work for your use case, so please check carefully for your usecase before using.

Copy of a Single Module Without Dependencies

Trying with java version 15u36 that has no dependencies:

[~]$ cat /opt/psi/Programming/Java/15u36/share/Programming/Java/dependencies
[~]$

Copying the content with:

# replace DESTINATION and NEW_PMODULE_BASE according to your needs
DESTINATION=root@ra-s-003
NEW_PMODULE_BASE=/opt/psi
rsync -avz /opt/psi/Programming/Java/15u36/ ${DESTINATION}:${NEW_PMODULE_BASE}/Programming/Java/15u36/
rsync -avz /opt/psi/Programming/modulefiles/Java/15u36 ${DESTINATION}:${NEW_PMODULE_BASE}/Programming/modulefiles/Java/15u36
rsync -avz /opt/psi/Programming/modulefiles/Java/.release-15u36 ${DESTINATION}:${NEW_PMODULE_BASE}/Programming/modulefiles/Java/.release-15u36

Then trying to use it:

[~]$ module avail
-------------------------------- Programming --------------------------------
Java/15u36
[~]$ module load Java/15u36
[~]$ java --version
openjdk 15 2020-09-15
OpenJDK Runtime Environment (build 15+36-1562)
OpenJDK 64-Bit Server VM (build 15+36-1562, mixed mode, sharing)

To automate the copy of a single module, you can use the following function:

# replace DESTINATION and NEW_PMODULE_BASE according to your needs
DESTINATION=root@ra-s-003
NEW_PMODULE_BASE=/opt/psi

copy_pmodule() {
  group=$1
  module=$2
  version=$3
  
  modulefile=/opt/psi/$group/modulefiles/$module/$version
  release=/opt/psi/$group/modulefiles/$module/.release-$version
  software=/opt/psi/$group/$module/$version/
  
  ssh $DESTINATION "mkdir -p $NEW_PMODULE_BASE/$group/$module/$version/"
  ssh $DESTINATION "mkdir -p $NEW_PMODULE_BASE/$group/modulefiles/$module/"
  
  for i in $modulefile $release $software
  do
    rsync -avz $i $DESTINATION:$i
  done
}

So now a single module can be copied with e.g.:

module_copy Programming cuda 12.8.1

Copy of a Module Including the Dependencies

To determine the dependencies, you can use the following functions:

get_group() {
  module=$1
  module search -a $module --no-header 2>&1 | head -1 |awk '{print $3}'
}

get_info() {
  group=$1
  module=$2
  version=$3
  if [[ ! -f /opt/psi/$group/modulefiles/$module/$version ]]
  then
    echo "****** ERROR. /opt/psi/$group/modulefiles/$module/$version not found"
  else
  cat /opt/psi/$group/modulefiles/$module/$version |grep -i maintainer|sed 's/module-maintainer[ \t]*//'
  fi
}

get_deps() {
  local module=$1
  local version=$2
  local space=${3:-0}
  
  for i in $(seq $space)
  do
    echo -n " "
  done
  
  group=$(get_group $module/$version)
  info=$(get_info $group $module $version)
  ALIGN=$(expr 40 - $space)
  printf "%-${ALIGN}s %s\n" "$module/$version" "($info)"
  dependency_file_1=/opt/psi/$group/modulefiles/$module/.deps-$version
  dependency_file_2=/opt/psi/$group/$module/$version/.dependencies
  
  if [[ -f $dependency_file_1 && -f $dependency_file_2 ]]
  then
    echo "Both dependency file exit. Error"
  return
  fi
  
  if [[ ! -f $dependency_file_1 && ! -f $dependency_file_2 ]]
  then
    return
  fi
  
  dependency_file=$dependency_file_1
  
  if [[ -f $dependency_file_2 ]]
  then
    dependency_file=$dependency_file_2
  fi
  
  for dep in $(cat $dependency_file|sed '/^$/d')
  do
    module=$(echo $dep|cut -d '/' -f 1)
    version=$(echo $dep|cut -d '/' -f 2)
    group=$(get_group $module/$version)
    get_deps $module $version $(expr $space + 3)
  done
}

We get the following dependencies for crystfel 0.10.2:

[~]$ get_deps crystfel 0.10.2
crystfel/0.10.2 ("Dmitry Ozerov <dmitry.ozerov@psi.ch>")
gcc/12.1.0 ("Achim Gsell <achim.gsell@psi.ch>")
hdf5_serial/1.12.2 (****** ERROR. /opt/psi/Compiler/modulefiles/hdf5_serial/1.12.2 not found)
pinkindexer/2021.08 ("Dmitry Ozerovv<dmitry.ozerov@psi.ch>")
xgandalf/2021.08 ("Dmitry Ozerov <dmitry.ozerov@psi.ch>")
fdip/2021.08 ("Dmitry Ozerov <dmitry.ozerov@psi.ch>")
xds/20250523 ("MX Data <jiaxin.duan@psi.ch>")
mosflm/7.4.0 ("MX Data <mx-software@psi.ch>")
HDF5_bitshuffle/2025.03 ("Filip Leonarski <filip.leonarski@psi.ch>")
HDF5_LZ4/2018.05 ("Dmitry Ozerov <dmitry.ozerov@psi.ch>")
DirAx/1.17 ("Dmitry Ozerov <dmitry.ozerov@psi.ch>")

As the dependencies are already resolved recursively, you can now simply copy all the listed modules with the copy function defined above.

Example for crystfel 0.10.2:

for get_deps crystfel 0.10.2 | cut -d ' ' -f 1
do
  module=$(echo $dep|cut -d '/' -f 1)
  version=$(echo $dep|cut -d '/' -f 2)
  copy_pmodule $group $module $version
done