HPCinstall
is a piece of software used to install other software in an HPC environment.
What it does is simply to run a given install script, but it will
help by automatize the clerical, tedious tasks, letting the script do only the complicated parts.
It interfaces and helps create modulefiles (particularly for lmod)
but it can be easily used also in a module-free environement.
See the module and installation workflow currently in use at NCAR/CISL.
- python 2.7+ (it may work with 2.6 +
argparse
) - bash (tested with v4.1 and v4.2, it should work with most versions)
- ssh (tested with OpenSSH v5.3 and v6.6, it should work with most versions)
- lmod or module (optional, tested with lmod v4.2 and v7.2, it should work with most versions)
- python
yaml
andblessed
modules (distributed with HPCInstall itself, see subdirectories, so they are not an external dependency)
Some of the features of HPCinstall
are:
- 🚀 automatic log of everything (environment, log, script used for install, etc)
- 👍 automatic archive of the logs in the install directory
- 😄 automatic generation of the install directory name (and module name) from
the name and version of the software to be compiled and the loaded compiler/mpi modules (if appropriate).
The structure of this directories names can be configured with the
sw_install_struct
andmod_install_struct
config properties - ✅ checksum verification of the installation (at install time and post-mortem with
hashdir
) - 🍺 and more
HPCInstall is simply invoked as
hpcinstall [options] filename
where filename
is the build/install script for the software to be installed
The CLI options for HPCInstall are just a few:
usage: hpcinstall [-h] [-c] [-f] [-d] [-p] install-software-ver
positional arguments:
install-software-ver script in the current directory which does the build
and install (do not use './', relative nor fully
qualified paths)
optional arguments:
-h, --help show this help message and exit
-c, --csgteam Install as csgteam (default: False)
-f, --force Force overwrite of existing install (default: False)
-d, --debug Debug mode i.e. more verbose output (default: False)
-p, --preserve Preserve current environment - not valid with
--csgteam (default: False)
The most useful one is --csgteam
which will cause the installation to be system-wide.
The --debug
and --preserve
are useful for debugging issues, and the --force
is a
convenience option to remove the target installation directory, because otherwise HPCInstall
will refuse to clobber it.
Your script can and should communicate with HPCInstall some important matters, using directives which are comments in the script of the form
#HPCI -n software_name # software_name is what is under installation
#HPCI -v software_version # software_version of what is under installation
#HPCI -a filename # archive this file in the same way as the build logs
#HPCI -x export FOO=bar # execute this line, preferred way to change the environment
#HPCI -l intel # load these modules, prefferred way to do so
#HPCI -p python numpy # load these modules, and signal they are prerequisites
#HPCI -o CLOBBER # clobber (overwrite without deleting) the existing install directory
-
All the directives, besides
-n
and-v
can appear several times and they will be managed in the order they appear. -
The values set with
-n
and-v
are usually used to construct the install directory and module directory (depending on how HPCInstalled has been configured, see the installation section below). -
The
-o
directive can be used to set options, at the moment only CLOBBER is supported. It is recommended that CLOBBER is not used unless strongly needed for particular use cases, and to make sure it is used only when needed, a confirmation message is asked twice. -
The values set with
-a
is a file that will be copied in the directory with installation logs, useful, e.g. to preserve a tarballs or other scripts (however use of here document is recommended) -
Whatever follows
-x
is executed verbatim in the shell before invoking the script. It could be simply included in the script instead of using this directive, however using the directive will inform HPCInstall that these things will change the environment, and that can be extremely useful especially when sourcing third part files (because HPCInstall will automatically store the environment after running the-x
commands, but before anything else in the script is exectuted) -
The
-l
and-p
directives simply load the specified modules (without the need to writemodule load
) and will inform HPCInstall that the environment has changed, like in the previous bullet. HPCInstall will runmodule purge
before anything else, and therefore any desired module must be explicitly loaded. There is no directive for other module commands such asreset
oruse
however they can be run in the-x
directive when needed. Moreover, the-p
can help creating the module for the software under installation, by setting the$HPCI_MOD_PREREQ
environmental variable -
The directives are exectuted in the order they appear, so if there are dependent modules (or
module use
or other order-sensitive items, they are honored)
HPCInstall will set the following environmental variables:
HPCI_SW_DIR # where to install the software
HPCI_SW_NAME # software_name of the sw being installed
HPCI_SW_VERSION # software_version of the sw being installed
HPCI_MOD_DIR # directory where to create module, generic
HPCI_MOD_DIR_IDEP # directory where to create module, if compiler independant
HPCI_MOD_DIR_CDEP # directory where to create module, if compiler dependant
HPCI_MOD_PREREQ # module prerequisite
These environmental variables should be used by the install script. Depending on how hpcinstall
has been installed, these environmental variables can use the loaded modules (e.g. compiler)
to build the appropriate directory structure, e.g. for where to install the software
or where to create the modules. This can happen only if HPCInstall
knows about the loaded
modules, i.e. if they are loaded via a directive and not in the body of the script.
And here is an example install script using directives and environmental variables, similar to
the build-mycode-example
present in the repository. It can have any name. Only bash
scripts are officially supported, and the recommended way to use anything non-bash is
to have it in a here document or in a
separate file, and invoke it from bash, as opposed to have a shebang for anything non-bash.
#!/bin/bash
#HPCI -n my_code
#HPCI -v 1.2.3
#HPCI -a ../my_code-1.2.3.tgz
#HPCI -l ncarenv
#HPCI -l gnu # modules can be loaded on same line or multiple lines
#HPCI -p netcdf # even if they are prerequisite modules, however, the order
#HPCI -p ncl # of their dependency must be respected
#HPCI -p another_module
#HPCI -p yet many other modules here
# terminate this script immediately should anything go wrong
set -e
./configure --prefix=$HPCI_SW_DIR
make
make install
# Create the module directory, if needed
# if this were compiler-independent module $HPCI_MOD_DIR_IDEP would have been used
mkdir -p $HPCI_MOD_DIR_CDEP/$HPCI_SW_NAME/
# Create the module with the following template
cat << EOF > $HPCI_MOD_DIR_CDEP/$HPCI_SW_NAME/${HPCI_SW_VERSION}.lua
require("posix")
whatis("$HPCI_SW_NAME v$HPCI_SW_VERSION")
help([[
This module loads my_code.
See http://my_code.example.com/ for details.
]])
local verpath = "$HPCI_SW_DIR" -- specific version path
local binpath = pathJoin(verpath, "bin") -- internal python libs
-- similarly for includes or others
prepend_path("PATH", binpath)
prereq($HPCI_MOD_PREREQ)
EOF
-
Convenience
-
👍 The above script will have only two lines changed when a new version of my_code is released, namely the two lines specifying
1.2.3
-
🚀 Without the script doing anything, everything during the build process is automatically logged and stored alongside the install directory: environment variables, output/error logs, script used for install, etc.
-
☁️ The install script is also pushed to a remote github repo (if HPCInstall is so configured at install time)
-
😄 The install directory name (and related module directory and module name) are automatically generated using HPCInstall configuration, without the script needing to do anything.
-
Simplification of tests and verifications
-
😎 Nothing will need to change in the script between a test install and a production install Just adding the
-c
command line argument the install will switch from test location to production location -
✅ Checksums, and file properties are automatically computed and logged each time a software is installed. The
hashdir
program is provided, to check if anybody changed anything when things do not work anymore -
Simply, the person doing the install can concentrate on the important things instead of the housekeeping.
Simply run something like hpcinstall build-mycode
. The build-mycode
script does
not need to be executable, but will be made so by HPCInstall
itself.
You should see an output similar to:
Saving environment status in hpci.env.log... Done.
Saving module list in hpci.modules.log... Done.
On 2017-02-16T13:37:22.883029 ddvento
called HPCinstall from /path/to/hpcinstall.py
invoked as /path/to/hpcinstall build-mycode
Setting environmental variables:
HPCI_SW_DIR = /glade/scratch/ddvento/test_installs/my_code/1.2.3/gnu/4.8.2/
HPCI_SW_NAME = my_code
HPCI_SW_VERSION = 1.2.3
HPCI_MOD_DIR = /glade/scratch/ddvento/test_installs/modulefiles/
HPCI_MOD_DIR_IDEP = /glade/scratch/ddvento/test_installs/modulefiles/idep/
HPCI_MOD_DIR_CDEP = /glade/scratch/ddvento/test_installs/modulefiles/gnu/
HPCI_MOD_PREREQ = "netcdf","ncl"
Running ./build-mycode-example...
Value of SOMETHING=3
This script pretends to be installing
my_code version v1.2.3 in /glade/scratch/ddvento/test_installs/my_code/1.2.3/gnu/4.8.2/.
And modules in one of /glade/scratch/ddvento/test_installs/modulefiles/
or /glade/scratch/ddvento/test_installs/modulefiles/gnu/
or /glade/scratch/ddvento/test_installs/modulefiles/idep/
using prerequisite module "netcdf","ncl"
PRETENDING TO BE RUNNING: ./configure --prefix=/glade/scratch/ddvento/test_installs/my_code/1.2.3/gnu/4.8.2/
PRETENDING TO BE RUNNING: make and make install
Done running ./build-mycode-example - exited with code 0
For more details about this code, see URL: http://www.example.com
Hashdir: d41d8cd98f00b204e9800998ecf8427e /glade/scratch/ddvento/test_installs/my_code/1.2.3/gnu/4.8.2
Connection to localhost closed.
Note the line that says:
Done running ./build-mycode-example - exited with code 0
⭐ HPCInstall
simply run the bash
script as is, and by default bash scripts keep running even in case
of errors. It is strongly recommended to use set -e
as the example does, to force bash to stop when an error
is encountered, in order to prevent partially failed builds to install.
From the previous run, the following logs will be created in the running directory and will also be
copied in the install directory in the BUILD_DIR
subdirectory. Such a directory will be
automatically created by HPCInstall
.
hpci.env.log
: contains the list of all the environment variables in the system, right before the script started executinghpci.modules.log
: contains the list of all the loaded modules, right before the script is executedhpci.main.log
: contains a log of what happened, including the checksum of the installed directoryhpci.build-mycode-example-20170216T133722.log
: contains the stdout and stderr produced by the scriptbuild-mycode
itself. The suffix is the isoformat datetime of the run, to avoid clobbering in case of repeated builds (e.g. when debugging a build issue)hpci.fileinfo.log
with some information about the files it installed
If modules or environmental settings are created by the -x
, -l
and -p
directives, their effect
is logged into the hpci.env.log
and hpci.modules.log
. If they are done in the body of the
script outside of a directive, they will not.
Note that in the BUILD_DIR
tree, HPCInstall
will also copy the script that ran, and anything
specified under the -a
(archive) directive, for reproducibility.
The installations described above occur in a test_installs
tree (configurable at the time HPCInstall
is installed or at runtime with the HPCI_TEST_BASEPATH
environment
variable). When satisfied with the user-level test install, a site-wide install in a global path
may be desired. Since at NCAR this is done by the csgteam
group which is different from root,
a --csgteam
(abbreviated to -c
) is available. Simply run:
hpcinstall -c build-mycode
and the same things as before will happen, just the directories will be the global ones (configured
at the time HPCInstall
was installed)
- To verify the hash of an installation, checking if anybody has changed anything, run
hashdir -d /path/to/installed/directory
and compare its output to the one in /path/to/installed/directory/BUILD_DIR/hpci.main.log
.
The BUILD_DIR
directory is by default ignored by hashdir
(and by hpcinstall
at install
time). If the hashes differ, you may run hashdir with the -v
option to investigate further.
It will output details about each single file, which you can diff from the ones obtained at
install time, which are stored in /path/to/installed/directory/BUILD_DIR/hpci.fileinfo.log
.
You may also use hashdir -i
and -e
options to filter what exactly to hash.
-
⭐ The
--csgteam
(root) install is interactive! -
✨ After a successful
--csgteam
(root) install, the script is committed and pushed to the remotescript_repo
as configured at the timeHPCInstall
was installed. -
🔥 Last, but not least, one IMPORTANT CONSIDERATION ABOUT POSSIBLY INTERACTIVE SCRIPTS 🔥 The way
HPCInstall
talks to the subshell is such that you could miss a question and the installation may seem to hang. This happens for example when runningunzip
which will print something likereplace directory/file? [y]es, [n]o, [A]ll, [N]one, [r]ename:
if the content of the file you are unzipping will clobber existing ones. This is very complicated to fix (see NCAR#72 for details), but a easy workaround is to just hit enter if the installation will seem to hang. The enter will flush the buffer and show the question, however a caveat is that it may also accept the default choice which might not be what you want. See if the program you are running has a non-interactive option (e.g.unzip -o
). If not, you can try to use a here document, e.g.
program.exe << INPUT
yes
no
/this/directory/over/here
INPUT
or https://en.wikipedia.org/wiki/Expect
HPCInstall can be simply copied in a directory and invoked with fully qualified path, or
that directory can be put in the $PATH
. However it needs to be configured for the
particular machine, and to do so it needs a config.hpcinstall.yaml
file in the
installation directory.
The mandatory configuration options are:
-
scratch_tree
: The directory where temporary installs will happen isscratch_tree/$USER
(can be overriden by setting theHPCI_TEST_BASEPATH
environment variable) -
sw_install_dir
: The basepath of the tree where sofware will be installed -
sw_install_struct
: The structure of the tree where sofware will be installed -
mod_install_dir
: The directory tree where modules will be installed -
mod_install_struct
: The structure of the tree where modules will be installed
There are additional optional configuration options, namely:
use_modules
: must be a boolean, ifFalse
will not do anything module-related (default:True
)python_cmd
: HPCInstall is written in python. If python is not in the$PATH
or if the default version is too old, another one can be specified here with fully qualified path.script_repo
: if set to a directory, consider that directory as a clone of a repository where all the install scripts will be preserved. After a successful production installation, add the install script to that repository and push itgit_cmd
: fully qualified path of the git binary, to be run to preserve the install scripts per previous bullet. If the git binary in the$PATH
is new enough, no need to set this option.
The directory-related configuration options may use evironmental variables. See the .yaml
files for some
examples.
This section may become reduntant once github includes the tag message in their
release page but for now, here it is, simply the output of
git tag -n1
:
- v0.9 Initial release, decent enough to be installed on Yellowstone
- v0.9.1 now hpcinstall can self-install itself :-)
- v0.9.2 now enforcing clean slate in the environment
- v0.9.3 never push too early.... changing name because of that
- v0.9.4 Making sure the clean slate environment is usable, e.g. allowing to load modules
- v1.0 Several improvements, namely issues #23 #62 #63 #64 #65 (most important: proper parsing of names-with-slash and push-installscript-to-github
- v1.0.1 Wrong directory for modules on Yellowstone, otherwise identical to v1.0
- v1.0.2 Missing dependencies in the install script, otherwise identical to v1.0
- v1.0.3 Install script and config file for jellystone, otherwise identical to v1.0
- v1.0.4 Cheyenne settings, otherwise identical to v1.0
- v1.0rc Many bugs fixed, large and small, changed the file format to directives
- v1.0rc2 Second release canditate, fixing some serious bugs
- v1.0rc3 Fixing issues for Yellowstone, caused by default python being v2.6
- v1.0rc4 wildcards for the archive directive, tcsh, datetime instead of PID, more moduledirs
- v1.0rc5 Swapping the order of directories for both modules and install: MPI first and COMPILER second
- v1.1 Several minor features added and bug fixes; better documenation; see the commit history for details
- v1.1.1 Made the use of modules optionally configurable at install time, and used that option for HPCFL
- v1.2 Using x-tunneling when
ssh
ing into localhost, fixed configuration file on Yellowstone, first open source release - v1.2.1 Refactored the parse_command_line_argument method and got rid of the nasty ${SUDO_USER} is not expanded bug
- v1.2.2 Configuration issue on Cheyenne/Laramie: it was not using the correct ldmod environmental variable
- v1.2.3 Now handles shared-scratch space for test installs and a minor bug fix