Commit dfa7c524 authored by Pape, David (FWCC) - 139658's avatar Pape, David (FWCC) - 139658
Browse files

Merge branch 'dev' into master.

Changes:
* Testing main function
* Refactoring
* Using term "driver" instead of "runner"
* Adding license
parents ff62ffc0 16c90172
Pipeline #23818 passed with stages
in 3 minutes and 59 seconds
cmake_minimum_required(VERSION 3.13)
project(gitlab-hpc-runner
project(gitlab-hpc-driver
VERSION 0.1.1
LANGUAGES CXX
)
......
This diff is collapsed.
# GitLab HPC-Runner
# GitLab HPC Driver
GitLab custom runner for HPC jobs. The initial implementation will support SLURM and might be generalized in the future.
HPC driver to be used with GitLab CI custom executor. The initial implementation will support Slurm
and might be generalized in the future.
## Build status and coverage
## License
[![pipeline status](https://gitlab.hzdr.de/pape58/gitlab-ci-test/badges/master/pipeline.svg)](https://gitlab.hzdr.de/fwcc/gitlab-hpc-runner/commits/master)
[![coverage report](https://gitlab.hzdr.de/pape58/gitlab-ci-test/badges/master/coverage.svg)](https://gitlab.hzdr.de/fwcc/gitlab-hpc-runner/commits/master)
This software is licensed under [GPL v3](https://www.gnu.org/licenses/gpl-3.0.en.html). The
[CodeCoverage.cmake](cmake/CodeCoverage.cmake) script has a different license --- see the file
for more information.
## Documentation
A user guide can be found on
A user guide on the runner using this driver can be found on
[InfoHub](http://fwcc.pages.hzdr.de/infohub/software/gitlab/ci.html#experimental-hpc-runner).
Developers and system administrators can find documentation for the master branch on
[GitLab Pages](http://fwcc.pages.hzdr.de/gitlab-hpc-runner/). For any other branch the documentation
[GitLab Pages](http://fwcc.pages.hzdr.de/gitlab-hpc-driver/). For any other branch the documentation
can be built by following the instructions below.
## Build instructions
......
......@@ -41,6 +41,26 @@
# 2017-06-02, Lars Bilke
# - Merged with modified version from github.com/ufz/ogs
#
# 2019-05-06, Anatolii Kurotych
# - Remove unnecessary --coverage flag
#
# 2019-12-13, FeRD (Frank Dana)
# - Deprecate COVERAGE_LCOVR_EXCLUDES and COVERAGE_GCOVR_EXCLUDES lists in favor
# of tool-agnostic COVERAGE_EXCLUDES variable, or EXCLUDE setup arguments.
# - CMake 3.4+: All excludes can be specified relative to BASE_DIRECTORY
# - All setup functions: accept BASE_DIRECTORY, EXCLUDE list
# - Set lcov basedir with -b argument
# - Add automatic --demangle-cpp in lcovr, if 'c++filt' is available (can be
# overridden with NO_DEMANGLE option in setup_target_for_coverage_lcovr().)
# - Delete output dir, .info file on 'make clean'
# - Remove Python detection, since version mismatches will break gcovr
# - Minor cleanup (lowercase function names, update examples...)
#
# 2019-12-19, FeRD (Frank Dana)
# - Rename Lcov outputs, make filtered file canonical, fix cleanup for targets
#
# 2020-01-19, Bob Apthorpe
# - Added gfortran support
#
# USAGE:
#
......@@ -50,14 +70,33 @@
# include(CodeCoverage)
#
# 3. Append necessary compiler flags:
# APPEND_COVERAGE_COMPILER_FLAGS()
# append_coverage_compiler_flags()
#
# 3.a (OPTIONAL) Set appropriate optimization flags, e.g. -O0, -O1 or -Og
#
# 4. If you need to exclude additional directories from the report, specify them
# using the COVERAGE_LCOV_EXCLUDES variable before calling SETUP_TARGET_FOR_COVERAGE_LCOV.
# using full paths in the COVERAGE_EXCLUDES variable before calling
# setup_target_for_coverage_*().
# Example:
# set(COVERAGE_LCOV_EXCLUDES 'dir1/*' 'dir2/*')
# set(COVERAGE_EXCLUDES
# '${PROJECT_SOURCE_DIR}/src/dir1/*'
# '/path/to/my/src/dir2/*')
# Or, use the EXCLUDE argument to setup_target_for_coverage_*().
# Example:
# setup_target_for_coverage_lcov(
# NAME coverage
# EXECUTABLE testrunner
# EXCLUDE "${PROJECT_SOURCE_DIR}/src/dir1/*" "/path/to/my/src/dir2/*")
#
# 4.a NOTE: With CMake 3.4+, COVERAGE_EXCLUDES or EXCLUDE can also be set
# relative to the BASE_DIRECTORY (default: PROJECT_SOURCE_DIR)
# Example:
# set(COVERAGE_EXCLUDES "dir1/*")
# setup_target_for_coverage_gcovr_html(
# NAME coverage
# EXECUTABLE testrunner
# BASE_DIRECTORY "${PROJECT_SOURCE_DIR}/src"
# EXCLUDE "dir2/*")
#
# 5. Use the functions described below to create a custom make target which
# runs your test executable and produces a code coverage report.
......@@ -75,7 +114,7 @@ find_program( GCOV_PATH gcov )
find_program( LCOV_PATH NAMES lcov lcov.bat lcov.exe lcov.perl)
find_program( GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat )
find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test)
find_package(Python COMPONENTS Interpreter)
find_program( CPPFILT_PATH NAMES c++filt )
if(NOT GCOV_PATH)
message(FATAL_ERROR "gcov not found! Aborting...")
......@@ -86,12 +125,22 @@ if("${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang")
message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...")
endif()
elseif(NOT CMAKE_COMPILER_IS_GNUCXX)
message(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
if("${CMAKE_Fortran_COMPILER_ID}" MATCHES "[Ff]lang")
# Do nothing; exit conditional without error if true
elseif("${CMAKE_Fortran_COMPILER_ID}" MATCHES "GNU")
# Do nothing; exit conditional without error if true
else()
message(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
endif()
endif()
set(COVERAGE_COMPILER_FLAGS "-g --coverage -fprofile-arcs -ftest-coverage"
set(COVERAGE_COMPILER_FLAGS "-g -fprofile-arcs -ftest-coverage"
CACHE INTERNAL "")
set(CMAKE_Fortran_FLAGS_COVERAGE
${COVERAGE_COMPILER_FLAGS}
CACHE STRING "Flags used by the Fortran compiler during coverage builds."
FORCE )
set(CMAKE_CXX_FLAGS_COVERAGE
${COVERAGE_COMPILER_FLAGS}
CACHE STRING "Flags used by the C++ compiler during coverage builds."
......@@ -109,6 +158,7 @@ set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
CACHE STRING "Flags used by the shared libraries linker during coverage builds."
FORCE )
mark_as_advanced(
CMAKE_Fortran_FLAGS_COVERAGE
CMAKE_CXX_FLAGS_COVERAGE
CMAKE_C_FLAGS_COVERAGE
CMAKE_EXE_LINKER_FLAGS_COVERAGE
......@@ -118,10 +168,8 @@ if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading")
endif() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug"
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
link_libraries(gcov)
else()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
endif()
# Defines a target for running and collection code coverage information
......@@ -129,16 +177,22 @@ endif()
# NOTE! The executable should always have a ZERO as exit code otherwise
# the coverage generation will not complete.
#
# SETUP_TARGET_FOR_COVERAGE_LCOV(
# setup_target_for_coverage_lcov(
# NAME testrunner_coverage # New target name
# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
# DEPENDENCIES testrunner # Dependencies to build first
# BASE_DIRECTORY "../" # Base directory for report
# # (defaults to PROJECT_SOURCE_DIR)
# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
# # to BASE_DIRECTORY, with CMake 3.4+)
# NO_DEMANGLE # Don't demangle C++ symbols
# # even if c++filt is found
# )
function(SETUP_TARGET_FOR_COVERAGE_LCOV)
function(setup_target_for_coverage_lcov)
set(options NONE)
set(oneValueArgs NAME)
set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES LCOV_ARGS GENHTML_ARGS)
set(options NO_DEMANGLE)
set(oneValueArgs BASE_DIRECTORY NAME)
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES LCOV_ARGS GENHTML_ARGS)
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT LCOV_PATH)
......@@ -149,24 +203,56 @@ function(SETUP_TARGET_FOR_COVERAGE_LCOV)
message(FATAL_ERROR "genhtml not found! Aborting...")
endif() # NOT GENHTML_PATH
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
if(${Coverage_BASE_DIRECTORY})
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
else()
set(BASEDIR ${PROJECT_SOURCE_DIR})
endif()
# Collect excludes (CMake 3.4+: Also compute absolute paths)
set(LCOV_EXCLUDES "")
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_LCOV_EXCLUDES})
if(CMAKE_VERSION VERSION_GREATER 3.4)
get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
endif()
list(APPEND LCOV_EXCLUDES "${EXCLUDE}")
endforeach()
list(REMOVE_DUPLICATES LCOV_EXCLUDES)
# Conditional arguments
if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE})
set(GENHTML_EXTRA_ARGS "--demangle-cpp")
endif()
# Setup target
add_custom_target(${Coverage_NAME}
# Cleanup lcov
COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -directory . --zerocounters
COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -directory . -b ${BASEDIR} --zerocounters
# Create baseline to make sure untouched files show up in the report
COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -c -i -d . -o ${Coverage_NAME}.base
COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -c -i -d . -b ${BASEDIR} -o ${Coverage_NAME}.base
# Run tests
COMMAND ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
# Capturing lcov counters and generating report
COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --directory . --capture --output-file ${Coverage_NAME}.info
COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --directory . -b ${BASEDIR} --capture --output-file ${Coverage_NAME}.capture
# add baseline counters
COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -a ${Coverage_NAME}.base -a ${Coverage_NAME}.info --output-file ${Coverage_NAME}.total
COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --remove ${Coverage_NAME}.total ${COVERAGE_LCOV_EXCLUDES} --output-file ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned
COMMAND ${GENHTML_PATH} ${Coverage_GENHTML_ARGS} -o ${Coverage_NAME} ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned
COMMAND ${CMAKE_COMMAND} -E remove ${Coverage_NAME}.base ${Coverage_NAME}.total ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned
COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -a ${Coverage_NAME}.base -a ${Coverage_NAME}.capture --output-file ${Coverage_NAME}.total
# filter collected data to final coverage report
COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --remove ${Coverage_NAME}.total ${LCOV_EXCLUDES} --output-file ${Coverage_NAME}.info
# Generate HTML output
COMMAND ${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS} -o ${Coverage_NAME} ${Coverage_NAME}.info
# Set output files as GENERATED (will be removed on 'make clean')
BYPRODUCTS
${Coverage_NAME}.base
${Coverage_NAME}.capture
${Coverage_NAME}.total
${Coverage_NAME}.info
${Coverage_NAME} # report directory
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
DEPENDS ${Coverage_DEPENDENCIES}
......@@ -185,39 +271,56 @@ function(SETUP_TARGET_FOR_COVERAGE_LCOV)
COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
)
endfunction() # SETUP_TARGET_FOR_COVERAGE_LCOV
endfunction() # setup_target_for_coverage_lcov
# Defines a target for running and collection code coverage information
# Builds dependencies, runs the given executable and outputs reports.
# NOTE! The executable should always have a ZERO as exit code otherwise
# the coverage generation will not complete.
#
# SETUP_TARGET_FOR_COVERAGE_GCOVR_XML(
# setup_target_for_coverage_gcovr_xml(
# NAME ctest_coverage # New target name
# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
# DEPENDENCIES executable_target # Dependencies to build first
# BASE_DIRECTORY "../" # Base directory for report
# # (defaults to PROJECT_SOURCE_DIR)
# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
# # to BASE_DIRECTORY, with CMake 3.4+)
# )
function(SETUP_TARGET_FOR_COVERAGE_GCOVR_XML)
function(setup_target_for_coverage_gcovr_xml)
set(options NONE)
set(oneValueArgs NAME)
set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
set(oneValueArgs BASE_DIRECTORY NAME)
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT Python_FOUND)
message(FATAL_ERROR "python not found! Aborting...")
endif()
if(NOT GCOVR_PATH)
message(FATAL_ERROR "gcovr not found! Aborting...")
endif() # NOT GCOVR_PATH
# Combine excludes to several -e arguments
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
if(${Coverage_BASE_DIRECTORY})
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
else()
set(BASEDIR ${PROJECT_SOURCE_DIR})
endif()
# Collect excludes (CMake 3.4+: Also compute absolute paths)
set(GCOVR_EXCLUDES "")
foreach(EXCLUDE ${COVERAGE_GCOVR_EXCLUDES})
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES})
if(CMAKE_VERSION VERSION_GREATER 3.4)
get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
endif()
list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
endforeach()
list(REMOVE_DUPLICATES GCOVR_EXCLUDES)
# Combine excludes to several -e arguments
set(GCOVR_EXCLUDE_ARGS "")
foreach(EXCLUDE ${GCOVR_EXCLUDES})
string(REPLACE "*" "\\*" EXCLUDE_REPLACED ${EXCLUDE})
list(APPEND GCOVR_EXCLUDES "-e")
list(APPEND GCOVR_EXCLUDES "${EXCLUDE_REPLACED}")
list(APPEND GCOVR_EXCLUDE_ARGS "-e")
list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE_REPLACED}")
endforeach()
add_custom_target(${Coverage_NAME}
......@@ -226,9 +329,10 @@ function(SETUP_TARGET_FOR_COVERAGE_GCOVR_XML)
# Running gcovr
COMMAND ${GCOVR_PATH} --xml
-r ${PROJECT_SOURCE_DIR} ${GCOVR_EXCLUDES}
-r ${BASEDIR} ${GCOVR_EXCLUDE_ARGS}
--object-directory=${PROJECT_BINARY_DIR}
-o ${Coverage_NAME}.xml
BYPRODUCTS ${Coverage_NAME}.xml
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
DEPENDS ${Coverage_DEPENDENCIES}
COMMENT "Running gcovr to produce Cobertura code coverage report."
......@@ -239,40 +343,56 @@ function(SETUP_TARGET_FOR_COVERAGE_GCOVR_XML)
COMMAND ;
COMMENT "Cobertura code coverage report saved in ${Coverage_NAME}.xml."
)
endfunction() # SETUP_TARGET_FOR_COVERAGE_GCOVR_XML
endfunction() # setup_target_for_coverage_gcovr_xml
# Defines a target for running and collection code coverage information
# Builds dependencies, runs the given executable and outputs reports.
# NOTE! The executable should always have a ZERO as exit code otherwise
# the coverage generation will not complete.
#
# SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML(
# setup_target_for_coverage_gcovr_html(
# NAME ctest_coverage # New target name
# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
# DEPENDENCIES executable_target # Dependencies to build first
# BASE_DIRECTORY "../" # Base directory for report
# # (defaults to PROJECT_SOURCE_DIR)
# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
# # to BASE_DIRECTORY, with CMake 3.4+)
# )
function(SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML)
function(setup_target_for_coverage_gcovr_html)
set(options NONE)
set(oneValueArgs NAME)
set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
set(oneValueArgs BASE_DIRECTORY NAME)
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT Python_FOUND)
message(FATAL_ERROR "python not found! Aborting...")
endif()
if(NOT GCOVR_PATH)
message(FATAL_ERROR "gcovr not found! Aborting...")
endif() # NOT GCOVR_PATH
# Combine excludes to several -e arguments
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
if(${Coverage_BASE_DIRECTORY})
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
else()
set(BASEDIR ${PROJECT_SOURCE_DIR})
endif()
# Collect excludes (CMake 3.4+: Also compute absolute paths)
set(GCOVR_EXCLUDES "")
foreach(EXCLUDE ${COVERAGE_GCOVR_EXCLUDES})
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES})
if(CMAKE_VERSION VERSION_GREATER 3.4)
get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
endif()
list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
endforeach()
list(REMOVE_DUPLICATES GCOVR_EXCLUDES)
# Combine excludes to several -e arguments
set(GCOVR_EXCLUDE_ARGS "")
foreach(EXCLUDE ${GCOVR_EXCLUDES})
string(REPLACE "*" "\\*" EXCLUDE_REPLACED ${EXCLUDE})
list(APPEND GCOVR_EXCLUDES "-e")
list(APPEND GCOVR_EXCLUDES "${EXCLUDE_REPLACED}")
list(APPEND GCOVR_EXCLUDE_ARGS "-e")
list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE_REPLACED}")
endforeach()
add_custom_target(${Coverage_NAME}
......@@ -283,10 +403,12 @@ function(SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML)
COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${Coverage_NAME}
# Running gcovr
COMMAND ${Python_EXECUTABLE} ${GCOVR_PATH} --html --html-details
-r ${PROJECT_SOURCE_DIR} ${GCOVR_EXCLUDES}
COMMAND ${GCOVR_PATH} --html --html-details
-r ${BASEDIR} ${GCOVR_EXCLUDE_ARGS}
--object-directory=${PROJECT_BINARY_DIR}
-o ${Coverage_NAME}/index.html
BYPRODUCTS ${PROJECT_BINARY_DIR}/${Coverage_NAME} # report directory
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
DEPENDS ${Coverage_DEPENDENCIES}
COMMENT "Running gcovr to produce HTML code coverage report."
......@@ -298,11 +420,12 @@ function(SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML)
COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
)
endfunction() # SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML
endfunction() # setup_target_for_coverage_gcovr_html
function(APPEND_COVERAGE_COMPILER_FLAGS)
function(append_coverage_compiler_flags)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}")
endfunction() # APPEND_COVERAGE_COMPILER_FLAGS
endfunction() # append_coverage_compiler_flags
# from:
# https://devblogs.microsoft.com/cppblog/clear-functional-c-documentation-with-sphinx-breathe-doxygen-cmake/
#Look for an executable called sphinx-build
find_program(SPHINX_EXECUTABLE
NAMES sphinx-build
DOC "Path to sphinx-build executable")
find_program(SPHINX_EXECUTABLE sphinx-build)
include(FindPackageHandleStandardArgs)
#Handle standard arguments to find_package like REQUIRED and QUIET
find_package_handle_standard_args(Sphinx
"Failed to find sphinx-build executable"
SPHINX_EXECUTABLE)
find_package_handle_standard_args(Sphinx DEFAULT_MSG SPHINX_EXECUTABLE)
......@@ -12,12 +12,9 @@ set(DOXYGEN_WARN_NO_PARAMDOC YES)
doxygen_add_docs(xml
../src
COMMENT "Generating Doxygen XML output"
COMMENT "Generating Doxygen XML"
)
# based on:
# https://devblogs.microsoft.com/cppblog/clear-functional-c-documentation-with-sphinx-breathe-doxygen-cmake/
set(SPHINX_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(SPHINX_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}")
......@@ -32,12 +29,12 @@ add_custom_target(docs
-Drelease="${PROJECT_VERSION}"
# breathe parameters
-Dbreathe_projects.runner="${SPHINX_BUILD_DIR}/xml"
-Dbreathe_projects.driver="${SPHINX_BUILD_DIR}/xml"
# exhale parameters
-Dexhale_args.containmentFolder="${EXHALE_CONTAINMENT_FOLDER}" # must be in source dir :-/
"${SPHINX_SOURCE_DIR}" "${SPHINX_BUILD_DIR}"
DEPENDS xml
COMMENT "Generating Sphinx documentation"
COMMENT "Generating documentation"
)
......@@ -12,7 +12,7 @@ make install
# Configuration
The program will read the configuration file located at `~/.config/gitlab-hpc-runner.cfg`. You can
The program will read the configuration file located at `~/.config/gitlab-hpc-driver.cfg`. You can
configure the following variables:
- `unified_output` (boolean)
......@@ -21,7 +21,7 @@ configure the following variables:
- possible values: **true**, false
- `logging_directory` (string)
- specifies where log files will be written
- example: `logging_directory = "/var/logs/runner/"`
- example: `logging_directory = "/var/logs/hpc-driver/"`
- `log_level` (string)
- specifies the level of detail of the logs
- possible values: trace, debug, **info**, warning, error, critical, off, null (= off)
......
......@@ -41,8 +41,8 @@ source_suffix = {
}
# will be set by CMake
breathe_projects = { 'runner': '' }
breathe_default_project = 'runner'
breathe_projects = { 'driver': '' }
breathe_default_project = 'driver'
exhale_args = {
"containmentFolder": "",
......
.. GitLab HPC Runner documentation master file, created by
sphinx-quickstart on Thu Nov 21 15:37:32 2019.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to GitLab HPC Runner's documentation!
Welcome to GitLab HPC Driver's documentation!
=============================================
.. toctree::
......@@ -21,7 +16,7 @@ Welcome to GitLab HPC Runner's documentation!
.. toctree::
:caption: More
GitLab Repository <https://gitlab.hzdr.de/fwcc/gitlab-hpc-runner>
GitLab Repository <https://gitlab.hzdr.de/fwcc/gitlab-hpc-driver>
Indices and tables
==================
......
This is a custom GitLab runner that allows users to run their CI jobs on HPC clusters. Currently,
the implementation utilizes the batch system [Slurm](https://slurm.schedmd.com/) but support for
other systems may be implemented later.
This is a driver for the GitLab runner custom executor that allows users to run their CI jobs on HPC
clusters. Currently, the implementation utilizes the batch system [Slurm](https://slurm.schedmd.com/)
but support for other systems may be implemented later.
# Architecture
......@@ -14,11 +14,12 @@ The runner service polls GitLab for new CI jobs. GitLab manages and prepares the
users. The runner service has a `config.toml` file that describes its runners. Each runner has tags
associated with it that can be specified when registering the runner with GitLab. Based on these
tags, GitLab can choose a runner to pass a CI job to -- depending on the tags a user specified in
their project's `.gitlab-ci.yml`. The runner then executes the job.
their project's `.gitlab-ci.yml`. The runner passes the job to its driver which then executes the
job.
Runners in general can utilize various executors. This project was implemented using the
[custom executor](https://docs.gitlab.com/runner/executors/custom.html) which allows for a custom
program to be specified to deal with the CI jobs. The runner service generates multiple bash scripts
driver to be specified to deal with the CI jobs. The runner service generates multiple bash scripts
for each job that are then passed to the custom program when calling it.
A CI job is split into four stages:
......@@ -43,7 +44,7 @@ The run stage is executed multiple times with the following sub-stages:
7. `archive_cache`
8. `upload_artifacts_on_success` / `upload_artifacts_on_failure`
In the config and cleanup stages the runner service calls the custom executable directly. In the run
In the config and cleanup stages the runner service calls the custom driver directly. In the run
stage it additionally passes the path to a bash script and the name of the current sub-stage to the
executable. For this project the three job stages that are implemented use the same program for
their execution. To allow it to distinguish between them, it is meant to be passed the name of the
......@@ -51,7 +52,8 @@ stage as first argument. This can be achieved by using the `<stage>_args` variab
`config.toml`. More information on configuring runners can be found in the
[GitLab Docs](https://docs.gitlab.com/runner/executors/custom.html#configuration).
In summary, a suitable configuration for the HPC runner may look something like this:
In summary, a suitable configuration for an HPC runner using this driver may look something like
this:
```toml
[[runners]]
......@@ -70,7 +72,7 @@ In summary, a suitable configuration for the HPC runner may look something like
cleanup_args = ["cleanup"]
```
# Design
<!-- # Design -->
<!-- TODO: -->
<!-- Explain classes, hierarchy, factories etc. -->
......
......@@ -9,7 +9,7 @@
* @brief Class to represent the CI environment.
*
* This class represents the environment the GitLab Runner service provides when calling the HPC
* runner.
* driver.
*/
class CIEnvironment : public Environment {
......
......@@ -6,7 +6,7 @@
#include "CIEnvironment.h"
#include "CIJobFactory.h"
#include "libconfig.h++"
#include "config.h"
#include "logging.h"
#include "spdlog/spdlog.h"
......@@ -25,7 +25,7 @@
*
* How this program is called:
*
* <tt>gitlab-hpc-runner (config | run \<script_path\> \<substage\> | cleanup)</tt>
* <tt>gitlab-hpc-driver (config | run \<script_path\> \<substage\> | cleanup)</tt>
*/
int main(int argc, char *argv[]) {
std::string h;
......@@ -35,23 +35,11 @@ int main(int argc, char *argv[]) {
std::cerr << "Could not get home directory" << std::endl;
return 50;
}
std::filesystem::path home(h);
std::filesystem::path cfgFile = home / ".config"
/ (program_invocation_short_name + std::string(".cfg"));
libconfig::Config config;
try {
config.readFile(cfgFile.c_str());
} catch(const libconfig::FileIOException &fioex) {
std::cerr << "I/O error while reading config file " << cfgFile
<< ": " << fioex.what() << std::endl;
return 40;
} catch(const libconfig::ParseException &pex) {
std::cerr << "Error parsing config file at " << pex.getFile() << ":" << pex.getLine()
<< ": " << pex.getError() << std::endl;
return 39;
}
std::unique_ptr<libconfig::Config> config(config::make(home));
if (config == nullptr)
return 51;