# 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/ ```{note} 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/): ```yaml 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: ```yaml 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). ```yaml 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: ```bash [~]$ cat /opt/psi/Programming/Java/15u36/share/Programming/Java/dependencies [~]$ ``` Copying the content with: ```bash # 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: ```bash [~]$ 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: ```bash # 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.: ```bash module_copy Programming cuda 12.8.1 ``` ### Copy of a Module Including the Dependencies To determine the dependencies, you can use the following functions: ```bash 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: ```bash [~]$ get_deps crystfel 0.10.2 crystfel/0.10.2 ("Dmitry Ozerov ") gcc/12.1.0 ("Achim Gsell ") hdf5_serial/1.12.2 (****** ERROR. /opt/psi/Compiler/modulefiles/hdf5_serial/1.12.2 not found) pinkindexer/2021.08 ("Dmitry Ozerovv") xgandalf/2021.08 ("Dmitry Ozerov ") fdip/2021.08 ("Dmitry Ozerov ") xds/20250523 ("MX Data ") mosflm/7.4.0 ("MX Data ") HDF5_bitshuffle/2025.03 ("Filip Leonarski ") HDF5_LZ4/2018.05 ("Dmitry Ozerov ") DirAx/1.17 ("Dmitry Ozerov ") ``` 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: ```bash 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 ```