From a0ce9e2e2d4a50ff03904ee712c7c36bc21b0a83 Mon Sep 17 00:00:00 2001 From: Alberto Miranda Date: Thu, 26 Oct 2023 12:41:16 +0200 Subject: [PATCH 1/4] Rename dir: `util` -> `cli` --- CMakeLists.txt | 2 +- {util => cli}/CMakeLists.txt | 0 {util => cli}/copy.cpp | 0 {util => cli}/ping.cpp | 0 {util => cli}/shutdown.cpp | 0 5 files changed, 1 insertion(+), 1 deletion(-) rename {util => cli}/CMakeLists.txt (100%) rename {util => cli}/copy.cpp (100%) rename {util => cli}/ping.cpp (100%) rename {util => cli}/shutdown.cpp (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1bbd57c..637faca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -320,9 +320,9 @@ else () endif () add_subdirectory(etc) +add_subdirectory(cli) add_subdirectory(lib) add_subdirectory(src) -add_subdirectory(util) if(CARGO_BUILD_TESTS) add_subdirectory(tests) diff --git a/util/CMakeLists.txt b/cli/CMakeLists.txt similarity index 100% rename from util/CMakeLists.txt rename to cli/CMakeLists.txt diff --git a/util/copy.cpp b/cli/copy.cpp similarity index 100% rename from util/copy.cpp rename to cli/copy.cpp diff --git a/util/ping.cpp b/cli/ping.cpp similarity index 100% rename from util/ping.cpp rename to cli/ping.cpp diff --git a/util/shutdown.cpp b/cli/shutdown.cpp similarity index 100% rename from util/shutdown.cpp rename to cli/shutdown.cpp -- GitLab From 4231f53ce0837005255fc8479b401afa9b14dd77 Mon Sep 17 00:00:00 2001 From: Alberto Miranda Date: Thu, 26 Oct 2023 12:58:17 +0200 Subject: [PATCH 2/4] Add `cargoctl` CLI util --- CMakeLists.txt | 15 ++++ cli/CMakeLists.txt | 20 ++++++ cli/cargoctl.in | 172 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 207 insertions(+) create mode 100755 cli/cargoctl.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 637faca..6a554d2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -149,6 +149,11 @@ message(STATUS "[${PROJECT_NAME}] server bind port: ${CARGO_BIND_PORT}") option(CARGO_BUILD_TESTS "Build tests (disabled by default)" OFF) +### MPI options that should be passed to ${MPIEXEC_EXECUTABLE} when starting +### the server via the `cargoctl` script +set(CARGOCTL_MPIEXEC_OPTIONS "--map-by node --oversubscribe" CACHE STRING + "Options passed to `${MPIEXEC_EXECUTABLE}` by `cargoctl` when starting the server") + set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # ############################################################################## @@ -324,6 +329,10 @@ add_subdirectory(cli) add_subdirectory(lib) add_subdirectory(src) +if (CARGO_SYSTEMD_SUPPORT) + add_subdirectory(systemd) +endif () + if(CARGO_BUILD_TESTS) add_subdirectory(tests) endif() @@ -334,6 +343,11 @@ endif() # using find_package() # ############################################################################## +set(BIN_INSTALL_DIR "${CMAKE_INSTALL_BINDIR}" + CACHE PATH "Path where ${PROJECT_NAME} binaries will be installed") +set(DATA_INSTALL_DIR "${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}" + CACHE PATH "Path where ${PROJECT_NAME} data files will be installed") + include(CMakePackageConfigHelpers) configure_package_config_file( @@ -341,6 +355,7 @@ configure_package_config_file( "${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}-${PROJECT_VERSION}" + PATH_VARS BIN_INSTALL_DIR DATA_INSTALL_DIR ) write_basic_package_version_file( diff --git a/cli/CMakeLists.txt b/cli/CMakeLists.txt index 9b47c00..d349e97 100644 --- a/cli/CMakeLists.txt +++ b/cli/CMakeLists.txt @@ -22,6 +22,19 @@ # SPDX-License-Identifier: GPL-3.0-or-later # ################################################################################ +################################################################################ +## cargoctl: A CLI tool to interact with a Cargo server +# TODO: This is a hack: `cargoctl` needs to know the full path to the +# installed `cargo` and `cargo_shutdown` programs but CMake doesn't seem to +# provide a way to get this information at this stage. Thus, we set it manually +# here :( +set(CARGO_PROGRAM ${CMAKE_INSTALL_FULL_BINDIR}/cargo) +set(CARGO_SHUTDOWN_PROGRAM ${CMAKE_INSTALL_FULL_BINDIR}/cargo_shutdown) +configure_file(cargoctl.in cargoctl @ONLY) + + +################################################################################ +## cargo_ping: A CLI tool to check if a Cargo server is running add_executable(cargo_ping) target_sources(cargo_ping @@ -37,6 +50,8 @@ target_link_libraries(cargo_ping cargo ) +################################################################################ +## cargo_shutdown: A CLI tool to shutdown a Cargo server add_executable(cargo_shutdown) target_sources(cargo_shutdown @@ -52,6 +67,8 @@ target_link_libraries(cargo_shutdown cargo ) +################################################################################ +## ccp: A CLI tool to request a Cargo server to copy files between storage tiers add_executable(ccp) target_sources(ccp @@ -70,3 +87,6 @@ target_link_libraries(ccp install(TARGETS cargo_ping cargo_shutdown ccp RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) + +install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/cargoctl + DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/cli/cargoctl.in b/cli/cargoctl.in new file mode 100755 index 0000000..ed81d0b --- /dev/null +++ b/cli/cargoctl.in @@ -0,0 +1,172 @@ +#!/bin/bash +################################################################################ +# Copyright 2022-2023, Barcelona Supercomputing Center (BSC), Spain # +# # +# This software was partially supported by the EuroHPC-funded project ADMIRE # +# (Project ID: 956748, https://www.admire-eurohpc.eu). # +# # +# This file is part of Cargo. # +# # +# Cargo is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# Cargo is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with Cargo. If not, see . # +# # +# SPDX-License-Identifier: GPL-3.0-or-later # +################################################################################ + +progname=$(basename "$0") + +usage() { + echo "Usage: $progname COMMAND " + echo "" + echo " -h, --help: Show this help message and exit" + echo "" + echo "Valid commands:" + echo "" + echo "Start a Cargo server listening on a address , with workers " + echo "distributed over a pool of hosts :" + echo " $progname start -s -H -n " + echo "" + echo "NOTE: ADDR must be a valid Mercury address, and host1, host2, ..., " + echo "hostN must be valid hostnames. Also, ADDR should refer to one of the " + echo "defined hosts in the host pool." + echo "" + echo "Stop a Cargo server listening on a given address :" + echo " $progname stop -s " + exit 1 +} + +start() { + if [ $# -eq 0 ]; then + echo "$progname: ERROR: No options provided" >&2 + usage + fi + + local OPTIND opt workers address + + while getopts ":s:H:n:" opt; do + case $opt in + s) + address="$OPTARG" + ;; + H) + hosts="$OPTARG" + ;; + n) + workers="$OPTARG" + ;; + \?) + echo "$progname: Invalid option: '-$OPTARG'" >&2 + usage + ;; + :) + echo "Option -$OPTARG requires an argument." >&2 + usage + ;; + esac + done + + if [ -z "$workers" ]; then + echo "$progname: ERROR: Number of workers not provided" >&2 + usage + fi + + if [ -z "$address" ]; then + echo "$progname: ERROR: Bind address not provided" >&2 + usage + fi + + echo "Starting the Cargo server" + echo " Hosts: $hosts" + echo " Workers: $workers" + echo " Master address: $address" + + if ! @MPIEXEC_EXECUTABLE@ \ + -H "$hosts" \ + -np "$workers" \ + @CARGOCTL_MPIEXEC_OPTIONS@ \ + @CARGO_PROGRAM@ --listen "$address"; then + echo "Failed to start the Cargo server" + exit 1 + fi +} + +stop() { + + if [ $# -eq 0 ]; then + echo "$progname: ERROR: No options provided" >&2 + usage + fi + + local OPTIND opt address + + while getopts ":s:" opt; do + case $opt in + s) + address="$OPTARG" + ;; + \?) + echo "$progname: Invalid option: '-$OPTARG'" >&2 + usage + ;; + :) + echo "Option -$OPTARG requires an argument." >&2 + usage + ;; + esac + done + + if [ -z "$address" ]; then + echo "$progname: ERROR: Server address not provided" >&2 + usage + fi + + echo "Stopping the Cargo server at $address" + @CARGO_SHUTDOWN_PROGRAM@ -s "$address" +} + +main() { + if [ $# -lt 1 ]; then + usage + fi + + echo "Running $progname $*" + + local cmd + + for arg in "$@"; do + case $arg in + "-h" | "--help") + usage + ;; + *) ;; + + esac + done + + while [ $# -gt 0 ]; do + case $1 in + "start" | "stop") + cmd="$1" + shift + "$cmd" "$@" + exit 0 + ;; + *) + echo "$progname: Invalid option: $1" >&2 + usage + ;; + esac + done +} + +main "$@" -- GitLab From 7716a4c34ec92bcda64734ce9ca085321da04cbc Mon Sep 17 00:00:00 2001 From: Alberto Miranda Date: Thu, 26 Oct 2023 18:27:51 +0200 Subject: [PATCH 3/4] Generate and install `systemd` service files --- CMakeLists.txt | 24 ++++++++---- cmake/systemd.cmake | 79 +++++++++++++++++++++++++++++++++++++++ systemd/CMakeLists.txt | 45 ++++++++++++++++++++++ systemd/cargo@.service.in | 11 ++++++ 4 files changed, 151 insertions(+), 8 deletions(-) create mode 100644 cmake/systemd.cmake create mode 100644 systemd/CMakeLists.txt create mode 100644 systemd/cargo@.service.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 6a554d2..4cd95f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,6 +97,10 @@ include(FetchContent) # that are substituted when generating defaults.cpp below include(GNUInstallDirs) +# CMakeDependentOption defines cmake_dependent_option() which is used to +# define options that depend on other options +include(CMakeDependentOption) + # Make sure that CMake can find our internal modules list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") @@ -154,6 +158,16 @@ option(CARGO_BUILD_TESTS "Build tests (disabled by default)" OFF) set(CARGOCTL_MPIEXEC_OPTIONS "--map-by node --oversubscribe" CACHE STRING "Options passed to `${MPIEXEC_EXECUTABLE}` by `cargoctl` when starting the server") +### systemd support +option(CARGO_SYSTEMD_SUPPORT "Enable systemd support (enabled by default)" ON) + +cmake_dependent_option( + CARGO_SYSTEMD_INSTALL_UNIT_FILES + "Install systemd unit files (disabled by default)" + OFF + "CARGO_SYSTEMD_SUPPORT" + OFF) + set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # ############################################################################## @@ -329,9 +343,9 @@ add_subdirectory(cli) add_subdirectory(lib) add_subdirectory(src) -if (CARGO_SYSTEMD_SUPPORT) +if(CARGO_SYSTEMD_SUPPORT) add_subdirectory(systemd) -endif () +endif() if(CARGO_BUILD_TESTS) add_subdirectory(tests) @@ -343,11 +357,6 @@ endif() # using find_package() # ############################################################################## -set(BIN_INSTALL_DIR "${CMAKE_INSTALL_BINDIR}" - CACHE PATH "Path where ${PROJECT_NAME} binaries will be installed") -set(DATA_INSTALL_DIR "${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}" - CACHE PATH "Path where ${PROJECT_NAME} data files will be installed") - include(CMakePackageConfigHelpers) configure_package_config_file( @@ -355,7 +364,6 @@ configure_package_config_file( "${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}-${PROJECT_VERSION}" - PATH_VARS BIN_INSTALL_DIR DATA_INSTALL_DIR ) write_basic_package_version_file( diff --git a/cmake/systemd.cmake b/cmake/systemd.cmake new file mode 100644 index 0000000..f6a51fe --- /dev/null +++ b/cmake/systemd.cmake @@ -0,0 +1,79 @@ +################################################################################ +# Copyright 2022-2023, Barcelona Supercomputing Center (BSC), Spain # +# # +# This software was partially supported by the EuroHPC-funded project ADMIRE # +# (Project ID: 956748, https://www.admire-eurohpc.eu). # +# # +# This file is part of Cargo. # +# # +# cargo is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# cargo is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with cargo. If not, see . # +# # +# SPDX-License-Identifier: GPL-3.0-or-later # +################################################################################ + + +include(CMakeParseArguments) + +#[=======================================================================[.rst: + + get_systemd_unit_directory(OUTPUT_VARIABLE [USER]) + +Initialize ``OUTPUT_VARIABLE`` to the directory where systemd unit files +are installed. This function will use ``pkg-config`` to find the information. +If ``USER`` is specified, the user unit directory will be returned instead. +#]=======================================================================] +function(get_systemd_unit_directory OUTPUT_VARIABLE) + + set(OPTIONS USER) + set(SINGLE_VALUE) + set(MULTI_VALUE) + + cmake_parse_arguments( + ARGS "${OPTIONS}" "${SINGLE_VALUE}" "${MULTI_VALUE}" ${ARGN} + ) + + if(ARGS_UNPARSED_ARGUMENTS) + message(WARNING "Unparsed arguments in get_systemd_unit_directory(): " + "this often indicates typos!\n" + "Unparsed arguments: ${ARGS_UNPARSED_ARGUMENTS}" + ) + endif() + + find_package(PkgConfig REQUIRED) + + # Check for the systemd application, so that we can find out where to + # install the service unit files + pkg_check_modules(SYSTEMD_PROGRAM QUIET systemd) + + if (ARGS_USER) + set(_pc_var systemduserunitdir) + else () + set(_pc_var systemdsystemunitdir) + endif () + + if (SYSTEMD_PROGRAM_FOUND) + # Use pkg-config to look up the systemd unit install directory + execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} + --variable=${_pc_var} systemd + OUTPUT_VARIABLE _systemd_unit_dir) + string(REGEX REPLACE "[ \t\n]+" "" _systemd_unit_dir "${_systemd_unit_dir}") + + message(STATUS "systemd services install dir: ${_systemd_unit_dir}") + + set(${OUTPUT_VARIABLE} + ${_systemd_unit_dir} + PARENT_SCOPE + ) + endif () +endfunction() diff --git a/systemd/CMakeLists.txt b/systemd/CMakeLists.txt new file mode 100644 index 0000000..1664618 --- /dev/null +++ b/systemd/CMakeLists.txt @@ -0,0 +1,45 @@ +################################################################################ +# Copyright 2022-2023, Barcelona Supercomputing Center (BSC), Spain # +# # +# This software was partially supported by the EuroHPC-funded project ADMIRE # +# (Project ID: 956748, https://www.admire-eurohpc.eu). # +# # +# This file is part of Cargo. # +# # +# Cargo is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# Cargo is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with Cargo. If not, see . # +# # +# SPDX-License-Identifier: GPL-3.0-or-later # +################################################################################ + +configure_file(cargo@.service.in cargo@.service @ONLY) + +# If requested, install the systemd unit files to the system directory +# for user-defined services. Otherwise, install them to the configured +# `datadir` directory (usually `/usr/share`). +if(CARGO_SYSTEMD_INSTALL_UNIT_FILES) + include(systemd) + get_systemd_unit_directory(SYSTEMD_UNIT_DIRECTORY USER) + + if(NOT SYSTEMD_UNIT_DIRECTORY) + message(FATAL_ERROR "Could not find systemd unit directory") + endif() + + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cargo@.service + DESTINATION ${SYSTEMD_UNIT_DIRECTORY} + ) +else() + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cargo@.service + DESTINATION ${CMAKE_INSTALL_DATADIR}/${CMAKE_PROJECT_NAME} + ) +endif() diff --git a/systemd/cargo@.service.in b/systemd/cargo@.service.in new file mode 100644 index 0000000..6e13006 --- /dev/null +++ b/systemd/cargo@.service.in @@ -0,0 +1,11 @@ +[Unit] +Description=Cargo parallel data stager + +[Service] +Type=simple +EnvironmentFile=%S/cargo/%I.cfg +ExecStart=@CMAKE_INSTALL_FULL_BINDIR@/cargoctl start -s ${CARGO_ADDRESS} -H ${CARGO_HOSTS} -n ${CARGO_NUM_NODES} +ExecStop=@CMAKE_INSTALL_FULL_BINDIR@/cargoctl stop -s ${CARGO_ADDRESS} +Restart=no +PrivateTmp=true +NoNewPrivileges=true -- GitLab From 755c6f351716f89e120db039e4d44070482622cf Mon Sep 17 00:00:00 2001 From: Alberto Miranda Date: Thu, 26 Oct 2023 18:28:39 +0200 Subject: [PATCH 4/4] Ensure Cargo consumers can find installed targets Directories `CMAKE_INSTALL_BINDIR` and `CMAKE_INSTALL_DATADIR` are now exported as package variables `CARGO_BIN_INSTALL_DIR` and `CARGO_DATA_INSTALL_DIR`. This allows consuming projects to retrieve these values by using `find_package(cargo)`. --- CMakeLists.txt | 6 ++++++ cmake/cargo-config.cmake.in | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4cd95f1..129a04a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -357,6 +357,11 @@ endif() # using find_package() # ############################################################################## +set(BIN_INSTALL_DIR "${CMAKE_INSTALL_BINDIR}" + CACHE PATH "Path where ${PROJECT_NAME} binaries will be installed") +set(DATA_INSTALL_DIR "${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}" + CACHE PATH "Path where ${PROJECT_NAME} data files will be installed") + include(CMakePackageConfigHelpers) configure_package_config_file( @@ -364,6 +369,7 @@ configure_package_config_file( "${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}-${PROJECT_VERSION}" + PATH_VARS BIN_INSTALL_DIR DATA_INSTALL_DIR ) write_basic_package_version_file( diff --git a/cmake/cargo-config.cmake.in b/cmake/cargo-config.cmake.in index 3e4fe70..8cb239b 100644 --- a/cmake/cargo-config.cmake.in +++ b/cmake/cargo-config.cmake.in @@ -28,4 +28,7 @@ check_required_components("@PROJECT_NAME@") include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Exports.cmake") -check_required_components("@PROJECT_NAME@") \ No newline at end of file +set_and_check(CARGO_BIN_INSTALL_DIR "@PACKAGE_BIN_INSTALL_DIR@") +set_and_check(CARGO_DATA_INSTALL_DIR "@PACKAGE_DATA_INSTALL_DIR@") + +check_required_components("@PROJECT_NAME@") -- GitLab