Skip to content

Commit

Permalink
Slurm plugin (#5)
Browse files Browse the repository at this point in the history
A large omnibus PR that adds support for SLURM.

* implement the slurm plugin
* CLI
    * many small improvements to the `uenv start` and `uenv run` commands
    * add the `uenv image ls` command
* testing:
    * setup scripts that create a test repo
    * install the bats bash testing framework for integration testing
    *  integration tests for the slurm plugin only
* template and helper script for building the slurm plugin RPM
  • Loading branch information
bcumming authored Sep 3, 2024
1 parent 42c3502 commit 46f1265
Show file tree
Hide file tree
Showing 69 changed files with 3,374 additions and 233 deletions.
2 changes: 1 addition & 1 deletion .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ BinPackParameters: true
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterControlStatement: MultiLine
AfterEnum: false
AfterFunction: false
AfterNamespace: false
Expand Down
2 changes: 1 addition & 1 deletion .clangd
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
CompileFlags:
Add: [-std=c++17, -Iinclude]
Add: [-std=c++20]
2 changes: 2 additions & 0 deletions .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ jobs:
- uses: actions/checkout@v4
- name: Update apt repositories for ccache
run: sudo apt update
- name: Install dependencies
run: sudo apt-get install util-linux libmount-dev slurm-wlm libslurm-dev slurmd slurmctld slurm-client
- name: Set up ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
Expand Down
29 changes: 29 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
BSD 3-Clause License

Copyright (c) 2023-2024, ETH Zürich
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58 changes: 36 additions & 22 deletions meson.build
Original file line number Diff line number Diff line change
@@ -1,38 +1,41 @@
project('uenv', ['cpp'],
default_options : [
'cpp_std=c++17',
'cpp_std=c++20',
'default_library=static',
],
version: files('VERSION'),
meson_version: '>=0.57')
version = meson.project_version()

#default_mount_point = get_option('default_mount_point')
uenv_slurm_plugin = get_option('slurm_plugin')
uenv_cli = get_option('cli')

conf_data = configuration_data()

# configure the dependencies
#

# use meson wrap to provide the dependencies, because the 'default_library=static' option
# will be propogated to each dependency, for a statically linked executable.
catch_dep = subproject('catch2', default_options: 'werror=false').get_variable('catch2_with_main_dep')
cli11_dep = subproject('cli11', default_options: 'werror=false').get_variable('CLI11_dep')
fmt_dep = subproject('fmt', default_options: 'werror=false').get_variable('fmt_dep')
json_dep = subproject('nlohmann_json', default_options: 'werror=false').get_variable('nlohmann_json_dep')
spdlog_dep = subproject('spdlog', default_options: 'werror=false').get_variable('spdlog_dep')
sqlite3_dep = subproject('sqlite3', default_options: 'werror=false').get_variable('sqlite3_dep')
catch_dep = subproject('catch2', default_options: ['werror=false', 'warning_level=0']).get_variable('catch2_with_main_dep')
cli11_dep = subproject('cli11', default_options: ['werror=false', 'warning_level=0']).get_variable('CLI11_dep')
fmt_dep = subproject('fmt', default_options: ['werror=false', 'warning_level=0']).get_variable('fmt_dep')
json_dep = subproject('nlohmann_json', default_options: ['werror=false', 'warning_level=0']).get_variable('nlohmann_json_dep')
spdlog_dep = subproject('spdlog', default_options: ['werror=false', 'warning_level=0','std_format=disabled','external_fmt=enabled']).get_variable('spdlog_dep')
sqlite3_dep = subproject('sqlite3', default_options: ['werror=false', 'warning_level=0']).get_variable('sqlite3_dep')

# the lib dependency is all of the common funtionality shared between the CLI
# and the slurm plugin.
lib_src = [
'src/uenv/cscs.cpp',
'src/uenv/env.cpp',
'src/uenv/envvars.cpp',
'src/uenv/lex.cpp',
'src/uenv/log.cpp',
'src/uenv/meta.cpp',
'src/uenv/parse.cpp',
'src/util/strings.cpp',
'src/uenv/repository.cpp',
'src/util/shell.cpp',
'src/util/strings.cpp',
'src/uenv/uenv.cpp',
]
lib_inc = include_directories('src')
Expand All @@ -44,25 +47,30 @@ lib_dep = declare_dependency(
)

# the uenv executable
uenv_src = [
'src/cli/env.cpp',
'src/cli/start.cpp',
'src/cli/uenv.cpp',
]
uenv_dep = [sqlite3_dep]
if uenv_cli
uenv_src = [
'src/cli/image.cpp',
'src/cli/ls.cpp',
'src/cli/run.cpp',
'src/cli/start.cpp',
'src/cli/uenv.cpp',
]
uenv_dep = [sqlite3_dep]

uenv = executable('uenv',
sources: uenv_src,
dependencies: [uenv_dep, lib_dep, fmt_dep, spdlog_dep, cli11_dep],
c_args: ['-DVERSION="@0@"'.format(version)],
install: true)
cli = executable('uenv',
sources: uenv_src,
dependencies: [uenv_dep, lib_dep, fmt_dep, spdlog_dep, cli11_dep],
c_args: ['-DVERSION="@0@"'.format(version)],
install: true)
endif

unit_src = [
'test/unit/env.cpp',
'test/unit/envvars.cpp',
'test/unit/parse.cpp',
'test/unit/lex.cpp',
'test/unit/main.cpp',
'test/unit/parse.cpp',
'test/unit/repository.cpp',
]

unit = executable('unit',
Expand All @@ -71,3 +79,9 @@ unit = executable('unit',
build_by_default: true,
install: false)

if uenv_slurm_plugin
subdir('src/slurm')
endif

# install the license
#install_data('LICENSE', install_mode : 'rw-r--r--', install_dir : 'license')
2 changes: 2 additions & 0 deletions meson_options.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
option('slurm_plugin', type: 'boolean', value: true)
option('cli', type: 'boolean', value: true)
34 changes: 34 additions & 0 deletions rpm/macros.meson
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
%__sourcedir .
%__builddir %{_target_platform}
%__meson_wrap_mode nodownload

%meson_setup \
mkdir -p %{__builddir} \
CFLAGS="${CFLAGS:-%optflags}"; export CFLAGS; \
CXXFLAGS="${CXXFLAGS:-%optflags}"; export CXXFLAGS; \
FFLAGS="${FFLAGS:-%optflags}"; export FFLAGS; \
FCFLAGS="${FCFLAGS:-%optflags}"; export FCFLAGS; \
meson setup %{__sourcedir} %{__builddir} \\\
%{?_enable_debug:-Ddebug=true} \\\
--prefix=%{_prefix} \\\
--bindir=%{_bindir} \\\
--sbindir=%{_sbindir} \\\
--libexecdir=%{_libexecdir} \\\
--libdir=%{_libdir} \\\
--localstatedir=%{_var} \\\
--sharedstatedir=%{_sharedstatedir} \\\
--includedir=%{_includedir} \\\
--datadir=%{_datadir} \\\
--sysconfdir=%{_sysconfdir} \\\
--mandir=%{_mandir} \\\
--infodir=%{_infodir} \\\
--localedir=%{_datadir}/locale \\\
-Dcli=false \\\
-Dslurm_plugin=true \\\
%{nil}

%meson_build \
meson compile %_smp_mflags -C %{__builddir}

%meson_install \
DESTDIR=%buildroot meson install --no-rebuild --skip-subprojects -C %{__builddir}
117 changes: 117 additions & 0 deletions rpm/make-rpm.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#!/bin/bash

usage="$(basename "$0") [-h] [-s,--skip-binary] [--slurm-version] dstdir
Helper script to create a source and binary rpm of the project.
Options:
-h,--help show this help text
-s,--skip-bin skip creation of binary package
--slurm-version slurm version to specify in RPM dependency, defaults to 20.11.9
"

# Default argument
RPM_SLURM_VERSION=20.11.9

# Initialize our own variables
skip_bin=0

# A temporary variable to hold the output of `getopt`
TEMP=$(getopt -o s,h --long skip-bin,help,slurm-version: -- "$@")

# If getopt has reported an error, exit script with an error
if [ $? != 0 ]; then
# echo 'Error parsing options' >&2
echo "${usage}" >&2
exit 1
fi

eval set -- "$TEMP"

# Now go through all the options
while true; do
case "$1" in
-s | --skip-bin)
skip_bin=1
shift
;;
--slurm-version)
shift
RPM_SLURM_VERSION="$1"
shift
;;
-h | --help)
shift
echo "${usage}"
exit 1
;;
--)
shift
break
;;
*)
echo "Internal error! $1"
exit 1
;;
esac
done

# Remaining dstdir is in $1
dstdir=$(realpath $1)

# Check if the positional argument was provided
if [ -z "$dstdir" ]; then
echo "${usage}" >&2
exit 1
fi

# Print the parsed arguments
echo "skip_bin=$skip_bin"
echo "dstdir=$dstdir"
echo "RPM_SLURM_VERSION=$RPM_SLURM_VERSION"

set -euo pipefail

# absolute path to this script (where the spec file is located)
_scriptdir=$(realpath "$(dirname "${BASH_SOURCE[0]}")")

# the project root directory
_projectdir=$(realpath "${_scriptdir}/../")

SLURM_UENV_MOUNT_VERSION=$(sed 's/-.*//' "${_scriptdir}/../VERSION")

rm -rf "${dstdir}"
mkdir -p "${dstdir}"

echo SLURM_UENV_MOUNT_VERSION=$SLURM_UENV_MOUNT_VERSION
echo _scriptdir=$_scriptdir
echo _projectdir=$_projectdir
tarball=slurm-uenv-mount-"${SLURM_UENV_MOUNT_VERSION}".tar.gz

(
cd "${dstdir}"

mkdir -p BUILD BUILDROOT RPMS SOURCES SPECS SRPMS

source_prefix="slurm-uenv-mount-${SLURM_UENV_MOUNT_VERSION}"

(
cd "${_projectdir}"
git archive --format=tar.gz --output="${dstdir}/SOURCES/${tarball}" HEAD
)

cp "${_scriptdir}/slurm-uenv-mount.spec" SPECS/
sed -i "s|UENVMNT_VERSION|${SLURM_UENV_MOUNT_VERSION}|g" SPECS/slurm-uenv-mount.spec
sed -i "s|RPM_SLURM_VERSION|${RPM_SLURM_VERSION}|g" SPECS/slurm-uenv-mount.spec

# create src rpm
rpmbuild -bs --define "_topdir ." SPECS/slurm-uenv-mount.spec

if [ "${skip_bin}" -eq "0" ]; then
# create binary rpm
rpmbuild --nodeps --define "_topdir $(pwd)" \
--define "set_build_flags CXXFLAGS=\"-O2 -Wall -Wpedantic\"" \
--define "_vpath_srcdir ${source_prefix}" \
--rebuild SRPMS/slurm-uenv-mount-*.src.rpm
fi
)
31 changes: 31 additions & 0 deletions rpm/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# For building RPMs.

RPM packaging requires that it performs the `meson setup ...`, `meson compile ...`
and `meson install ...` itself, in a controlled environment. The script provided
here drives that process, after making suitable sacrifices to the RPM packaging gods.

**WARNING**: the tools here build the RPM based on the state of the source code at `HEAD`
in the git repository. If you have uncommitted changes, they will not be reflected
in the generated RPM.

**NOTE**: building RPMs is fiddly business - it isn't you, it is `rpmbuild`. Contact
Ben or Simon for help instead of trying to find good docs on RPMs (they don't exist).

## make-rpm.sh

A script that will generate both source and binary RPMs for the project.

It requires a destination path where the RPM build will occur, and should be run in this path.

```
./rpm-build.sh $HOME/rpm/uenv
```

## macros.meson

The spec file `slurm-uenv-mount.spec` uses macros like `%meson_setup`, which parameterise
calls to meson. Macros for meson are not usually available, so we provide a definition of
the macros in `macros.meson`. They have been modified from the ones provided in the
following RPM:

https://packages.altlinux.org/en/sisyphus/binary/rpm-macros-meson/noarch/2908824343041241330
37 changes: 37 additions & 0 deletions rpm/slurm-uenv-mount.spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
Name: slurm-uenv-mount
Version: UENVMNT_VERSION
Release: RPM_SLURM_VERSION
Summary: SLURM spank plugin to mount squashfs images.
Prefix: /usr
Requires: slurm = RPM_SLURM_VERSION

License: BSD3
URL: https://github.com/eth-cscs/slurm-uenv-mount
Source0: %{name}-%{version}.tar.gz

BuildRequires: meson gcc slurm-devel

%define _build_id_links none

%description
A SLURM spank plugin to mount squashfs images.

%prep
%autosetup -c

%build
%meson_setup
%meson_build

%install
%meson_install

%post
REQ="required /usr/lib64/libslurm-uenv-mount.so"
CNF=/etc/plugstack.conf.d/99-slurm-uenv-mount.conf
mkdir -p /etc/plugstack.conf.d
echo "$REQ" > "$CNF"

%files
%license LICENSE
%{_libdir}/lib%{name}.so
Loading

0 comments on commit 46f1265

Please sign in to comment.