diff --git a/ci/check_rpcs.py b/ci/check_rpcs.py index 5055a07e363837f328eb6722a1b7b874282c0e24..fed1f1deba3459a19d96f89e1a53ab86b12b686e 100755 --- a/ci/check_rpcs.py +++ b/ci/check_rpcs.py @@ -1,11 +1,13 @@ #!/usr/bin/env python3 -from loguru import logger +import argparse +import itertools import re import sys from pathlib import Path -from typing import Dict +from typing import Dict, Iterable, Any, Optional from lark import Lark, Transformer +from loguru import logger RPC_NAMES = { 'ADM_ping', @@ -40,7 +42,7 @@ class Meta: @property def line(self): - return self._line + return self._line.replace('{', '{{').replace('}', '}}') @property def lineno(self): @@ -75,22 +77,21 @@ class RemoteProcedure: EXPR = re.compile(r""" ^(?P \[(?P\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\.\d+)]\s - \[(?P\w+)]\s + \[(?P\w+(?:-\w+)*?)]\s \[(?P\d+)]\s \[(?P\w+)]\s rpc\s + (?P<=|=>)\s + (?:pid:\s(?P\d+)\s)? id:\s(?P\d+)\s name:\s"(?P\w+)"\s (?:from|to):\s"(?P
.*?)"\s - (?P<=|=>)\s ) body:\s(?P.*)$ """, re.VERBOSE) - def __init__(self, is_client: bool, meta: Dict, body: Dict, - opts: Dict): + def __init__(self, meta: Dict, body: Dict, opts: Dict): - self._is_client = is_client self._meta = Meta( meta['line'], meta['lineno'], @@ -99,30 +100,26 @@ class RemoteProcedure: meta['pid'], meta['log_level']) + self._pid = int(meta['rpc_pid']) if meta['rpc_pid'] else None self._id = int(meta['rpc_id']) self._name = meta['rpc_name'] - self._is_request = meta['direction'] == '=>' + self._is_inbound = meta['direction'] == '<=' self._address = meta['address'] if opts: - assert self.is_client and self.is_reply self._op_id = opts['op_id'] else: - self._op_id = self.id + _, self._op_id = self.id self._body = body - @property - def is_client(self): - return self._is_client - @property def meta(self): return self._meta @property def id(self): - return self._id + return self._pid, self._id @property def op_id(self): @@ -141,16 +138,21 @@ class RemoteProcedure: return self._address @property - def is_request(self): - return self._is_request + def is_inbound(self): + return self._is_inbound @property - def is_reply(self): - return not self._is_request + def is_outbound(self): + return not self._is_inbound def __eq__(self, other): assert self.name == other.name + if self.name != other.name: + logger.critical("Attempting to compare RPCs with different names:\n" + f" self: {self}\n" + f" other: {other}\n") + sys.exit(1) # first, check that there are no extra keys in the body of the RPCs self_keys = set(self._body.keys()) @@ -165,8 +167,8 @@ class RemoteProcedure: logger.error( "\nExtra fields were found when comparing an rpc " "to its counterpart\n" - f" extra fields: {extra_keys}" - f" line number: {rpc.meta.lineno}" + f" extra fields: {extra_keys}\n" + f" line number: {rpc.meta.lineno}\n" f" line contents: {rpc.meta.line}", file=sys.stderr) return False @@ -185,18 +187,18 @@ class RemoteProcedure: def __repr__(self): return f'RemoteProcedure(' \ - f'is_client={self.is_client}, ' \ f'meta={self.meta}, ' \ f'op_id={self.op_id}, ' \ f'id={self.id}, ' \ f'name={self.name}, ' \ - f'is_request={self.is_request}, ' \ + f'is_inbound={self.is_inbound}, ' \ f'address="{self.address}", ' \ f'body="{self._body}"' \ f')' class Operation: + # noinspection PyShadowingBuiltins def __init__(self, id, request, reply): self._id = id self._request = request @@ -257,14 +259,16 @@ class BodyTransformer(Transformer): pair = tuple opts = dict dict = dict - true = lambda self, _: True - false = lambda self, _: False + true = lambda self, _: True # noqa + false = lambda self, _: False # noqa + # noinspection PyMethodMayBeStatic def start(self, items): body = dict(items[0]) opts = dict(items[1]) if len(items) == 2 else dict() return body, opts + # noinspection PyMethodMayBeStatic def number(self, n): (n,) = n try: @@ -272,14 +276,17 @@ class BodyTransformer(Transformer): except ValueError: return float(n) + # noinspection PyMethodMayBeStatic def escaped_string(self, s): (s,) = s return str(s[1:-1]) + # noinspection PyMethodMayBeStatic def string(self, s): (s,) = s return str(s) + # noinspection PyMethodMayBeStatic def ident(self, ident): (ident,) = ident return str(ident) @@ -291,85 +298,234 @@ def process_body(d): return BodyTransformer().transform(tree) -def find_rpcs(filename, is_client, rpc_name): +def sanitize(address): + if address and "://" in address: + return address.split("://")[1] + return address + + +def find_rpcs(filename, rpc_name): with open(filename, 'r') as f: for ln, line in enumerate(f, start=1): + + logger.trace(f"Processing line {ln}:") + logger.trace(f" {repr(line)}") + if m := RemoteProcedure.EXPR.match(line): tmp = m.groupdict() + # We found a line with a valid RPC format, but its name is not + # known to us. This can happen if the user has defined a new + # RPC and forgot to add it to RPC_NAMES, or if the user has + # made a typo. In any case, we should warn the user about this. + if (n := tmp['rpc_name']) not in RPC_NAMES: + logger.warning(f"Found RPC with unknown name '{n}', " + f"line ignored", file=sys.stderr) + continue + + # We found a line with a valid RPC format and its name is the + # one we are looking for. We can now parse the body of the RPC + # and yield it. if tmp['rpc_name'] == rpc_name: + logger.info( + f"Searching rpc name '{tmp['rpc_name']}' in " + f"line {ln} -- found") tmp['lineno'] = ln tmp['line'] = line body, opts = process_body(tmp['body']) del tmp['body'] - yield RemoteProcedure(is_client, tmp, body, opts) + yield RemoteProcedure(tmp, body, opts), ln + else: + logger.trace( + f"Searching rpc name '{tmp['rpc_name']}' in " + f"line {ln} -- not found") + else: + logger.warning(f"Failed to parse line {ln} in {filename}", + file=sys.stderr) -if __name__ == "__main__": +def process_file(file: Path, rpc_name: str, self_address: Optional[str], + targets: Optional[Iterable[str]] = None) -> Dict[ + int, Operation]: + """Extract information about RPCs from a logfile and create the necessary + Operation descriptors. Within one logfile, RPCs belonging to an operation + can be identified by their id (i.e. an RPC request and an RPC response + will share the same id). - if len(sys.argv) != 4: - print("ERROR: Invalid number of arguments", file=sys.stderr) - print( - f"Usage: {Path(sys.argv[0]).name} CLIENT_LOGFILE SERVER_LOGFILE RPC_NAME", - file=sys.stderr) - sys.exit(1) + Across logfiles, RPCs belonging to an operation can be identified by their + operation id, which corresponds to the rpc id in the server side and is + sent back to the client to allow matching. + + Example: + * client logfile: + [...] rpc <= id: 10 name: "ADM_ping" [args...] + [...] rpc => id: 10 name: "ADM_ping" [retval...] [op_id: 42] + + * server logfile: + [...] rpc => id: 42 name: "ADM_ping" [args...] + [...] rpc <= id: 42 name: "ADM_ping" [retval...] + + :param file: The path to logfile + :param rpc_name: The name of the RPC to search for + :param self_address: The address of the server that generated the logfile + (or None if unknown) + :return: A dict of Operations + """ + + ops = {} + file_rpcs = {} + valid_targets = targets or [] + + logger.info(f"Searching for RPC \"{rpc_name}\" in {file}\n" + f" self address: {self_address}") + + for rpc, lineno in find_rpcs(file, rpc_name): + + prefix, direction = ("in", "from") if rpc.is_outbound else ("out", "to") - client_logfile = Path(sys.argv[1]) - server_logfile = Path(sys.argv[2]) + logger.debug(f"Found {prefix}bound RPC to '{rpc.address}' with " + f"id '{rpc.id}' at line {lineno}") - for lf, n in zip([client_logfile, server_logfile], ['CLIENT_LOGFILE', - 'SERVER_LOGFILE']): - if not lf.is_file(): - logger.error(f"{n} '{lf}' is not a file", file=sys.stderr) + if sanitize(rpc.address) == sanitize(self_address): + logger.error(f"Found {prefix}bound RPC {direction} own address" + f" {rpc.meta.lineno}\n" + f" raw: '{rpc.meta.line}'", + file=sys.stderr) sys.exit(1) - rpc_name = sys.argv[3] + if rpc.id not in file_rpcs: + file_rpcs[rpc.id] = rpc + else: + req_rpc = file_rpcs[rpc.id] + del file_rpcs[rpc.id] + logger.debug(f"Creating new operation with id '{rpc.op_id}'") + ops[rpc.op_id] = Operation(rpc.op_id, req_rpc, rpc) + + return ops + + +def match_ops(origin_ops, target_ops, strict=True): + ec = True + + for op_id in origin_ops.keys(): + + if op_id not in target_ops: + logger.warning( + f"An operation with id '{op_id}' was found in origin's " + f"operations but is missing from target's operations") + if strict: + ec = False + continue + + if origin_ops[op_id] != target_ops[op_id]: + ec = False + + return ec + + +def configure_logging(verbosity): + logger.remove() + + if verbosity == 0: + log_level = "SUCCESS" + elif verbosity == 1: + log_level = "INFO" + elif verbosity == 2: + log_level = "DEBUG" + else: + log_level = "TRACE" + + logger.add(sys.stderr, level=log_level) + + +def group_by_pairs(it: Iterable[Any]): + for e1, e2 in zip(itertools.islice(it, 0, None, 1), + itertools.islice(it, 1, None, 1)): + yield e1, e2 + + +def main(): + parser = argparse.ArgumentParser( + description="Check that client and server logs match for a given RPC " + "name") + + parser.add_argument("RPC_NAME", + help="the name of the RPC to check") + parser.add_argument("LIBSCORD_LOGFILE", + type=Path, + help="the path to the scord client's logfile") + parser.add_argument("SCORD_LOGFILE", + type=Path, + help="the path to the scord server's logfile") + parser.add_argument("SCORD_ADDRESS", + type=str, + help="the address of the scord server") + parser.add_argument("SCORD_CTL_LOGFILE", + type=Path, + nargs='?', + help="the path to the scord server's logfile") + parser.add_argument("SCORD_CTL_ADDRESS", + type=str, + nargs='?', + help="the address of the scord-ctl server") + parser.add_argument( + "-v", + "--verbose", + help="enable verbose output (additional flags increase verbosity)", + action="count", + dest='verbosity') + + parser.set_defaults(verbosity=0) + args = parser.parse_args() + configure_logging(args.verbosity) + + logfiles = [args.LIBSCORD_LOGFILE, args.SCORD_LOGFILE] + argnames = ["LIBSCORD_LOGFILE", "SCORD_LOGFILE"] + origins = [None] + targets = [None, args.SCORD_ADDRESS] + + if args.SCORD_CTL_LOGFILE: + logfiles.append(args.SCORD_CTL_LOGFILE) + argnames.append("SCORD_CTL_LOGFILE") + + if not args.SCORD_CTL_ADDRESS: + parser.error( + "the following arguments are required: SCORD_CTL_ADDRESS") + origins.append(args.SCORD_ADDRESS) + targets.append(args.SCORD_CTL_ADDRESS) + + rpc_name = args.RPC_NAME + + for file, name in zip(logfiles, argnames): + if not file.is_file(): + logger.critical(f"{name} '{file}' is not a file", file=sys.stderr) + sys.exit(1) if rpc_name not in RPC_NAMES: - logger.error(f"'{rpc_name}' is not a valid rpc name", - file=sys.stderr) - logger.error(f" Valid names: {', '.join(sorted(RPC_NAMES))}", - file=sys.stderr) + logger.critical(f"'{rpc_name}' is not a valid rpc name", + file=sys.stderr) + logger.critical(f" Valid names: {', '.join(sorted(RPC_NAMES))}", + file=sys.stderr) sys.exit(1) - logfiles = [client_logfile, server_logfile] - client_side = [True, False] - client_ops = {} - server_ops = {} + file_ops = [] - # extract information about RPCs from logfiles and create - # the necessary Operation - for lf, is_client, ops in zip(logfiles, client_side, [client_ops, - server_ops]): + for file, self_address in zip(logfiles, targets): + ops = process_file(file, rpc_name, self_address) + file_ops.append((file, ops)) - found_rpcs = {} + for (origin_file, origin_ops), (target_file, target_ops) in \ + group_by_pairs(file_ops): - for rpc in find_rpcs(lf, is_client, rpc_name): - if rpc.id not in found_rpcs: - if rpc.is_request: - found_rpcs[rpc.id] = rpc - else: - logger.error(f"\nFound server reply for RPC without " - f"a corresponding client request at line" - f" {rpc.meta.lineno}\n" - f" raw: '{rpc.meta.line}'", file=sys.stderr) - sys.exit(1) - else: - req_rpc = found_rpcs[rpc.id] - req_rpc.op_id = rpc.op_id - ops[rpc.op_id] = Operation(rpc.op_id, req_rpc, rpc) - del found_rpcs[rpc.id] - - ec = 0 - for k in client_ops.keys(): + logger.info(f"Matching operations in '{origin_file.name}' and " + f"'{target_file.name}'") + if not match_ops(origin_ops, target_ops, False): + logger.critical("Not all operations match") + sys.exit(1) - if k not in server_ops: - logger.error( - f"Operation ID '{k}' found in client log but missing " - f"in server log") - ec = 1 + logger.success("All operations match") + sys.exit(0) - if client_ops[k] != server_ops[k]: - ec = 1 - sys.exit(ec) +if __name__ == "__main__": + main() diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 0de1b557568f15f9fb3462b0b995c6646c069c30..ff2512deb055fe8fe3ff354c8301057b3d3e546e 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -33,6 +33,9 @@ if(SCORD_BUILD_TESTS) set(TEST_ENV) list(APPEND TEST_ENV SCORD_LOG_OUTPUT=${TEST_DIRECTORY}/scord_daemon.log) + set(SCORD_ADDRESS_STRING + ${SCORD_TRANSPORT_PROTOCOL}://${SCORD_BIND_ADDRESS}:${SCORD_BIND_PORT}) + add_test(start_scord_daemon ${CMAKE_SOURCE_DIR}/scripts/runner.sh start scord.pid ${CMAKE_BINARY_DIR}/src/scord/scord -f @@ -48,6 +51,27 @@ if(SCORD_BUILD_TESTS) set_tests_properties(stop_scord_daemon PROPERTIES FIXTURES_CLEANUP scord_daemon) + + set(SCORD_CTL_TRANSPORT_PROTOCOL ${SCORD_TRANSPORT_PROTOCOL}) + set(SCORD_CTL_BIND_ADDRESS ${SCORD_BIND_ADDRESS}) + math(EXPR SCORD_CTL_BIND_PORT "${SCORD_BIND_PORT} + 1") + set(SCORD_CTL_ADDRESS_STRING + ${SCORD_CTL_TRANSPORT_PROTOCOL}://${SCORD_CTL_BIND_ADDRESS}:${SCORD_CTL_BIND_PORT}) + + add_test(start_scord_ctl + ${CMAKE_SOURCE_DIR}/scripts/runner.sh start scord-ctl.pid + ${CMAKE_BINARY_DIR}/src/scord-ctl/scord-ctl -l ${SCORD_CTL_ADDRESS_STRING} -o ${TEST_DIRECTORY}/scord_ctl.log + ) + + set_tests_properties(start_scord_ctl + PROPERTIES FIXTURES_SETUP scord_ctl) + + add_test(stop_scord_ctl + ${CMAKE_SOURCE_DIR}/scripts/runner.sh stop TERM scord-ctl.pid + ) + + set_tests_properties(stop_scord_ctl PROPERTIES FIXTURES_CLEANUP scord_ctl) + endif() add_subdirectory(c) diff --git a/examples/c/ADM_cancel_transfer.c b/examples/c/ADM_cancel_transfer.c index 8a3bc88d5de2249e4aa6cf568001296795806e5d..77bb2a0b2ecf5c768390990dce1225f6b274653f 100644 --- a/examples/c/ADM_cancel_transfer.c +++ b/examples/c/ADM_cancel_transfer.c @@ -36,14 +36,19 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fprintf(stderr, "ERROR: no location provided\n"); - fprintf(stderr, "Usage: ADM_cancel_transfer \n"); + test_info_t test_info = { + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + cli_args_t cli_args; + if(process_args(argc, argv, test_info, &cli_args)) { exit(EXIT_FAILURE); } int exit_status = EXIT_SUCCESS; - ADM_server_t server = ADM_server_create("tcp", argv[1]); + ADM_server_t server = ADM_server_create("tcp", cli_args.server_address); ADM_job_t job = NULL; ADM_node_t* job_nodes = prepare_nodes(NJOB_NODES); @@ -64,7 +69,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, + ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_connect_data_operation.c b/examples/c/ADM_connect_data_operation.c index 10398544879200167247455b52fa4515b7da4468..8ae8f55ea0a3ce493f1eca9288ae299f85f285f5 100644 --- a/examples/c/ADM_connect_data_operation.c +++ b/examples/c/ADM_connect_data_operation.c @@ -36,14 +36,19 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fprintf(stderr, "ERROR: no server address provided\n"); - fprintf(stderr, "Usage: ADM_connect_data_operation \n"); + test_info_t test_info = { + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + cli_args_t cli_args; + if(process_args(argc, argv, test_info, &cli_args)) { exit(EXIT_FAILURE); } int exit_status = EXIT_SUCCESS; - ADM_server_t server = ADM_server_create("tcp", argv[1]); + ADM_server_t server = ADM_server_create("tcp", cli_args.server_address); ADM_job_t job; ADM_node_t* job_nodes = prepare_nodes(NJOB_NODES); @@ -60,7 +65,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, + ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_define_data_operation.c b/examples/c/ADM_define_data_operation.c index 8b4fa0ca0e57248850cd392f053cf62fd28b4e7f..04a151c497c4e88b95c434b7a4b6506458e11a2e 100644 --- a/examples/c/ADM_define_data_operation.c +++ b/examples/c/ADM_define_data_operation.c @@ -36,15 +36,20 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fprintf(stderr, "ERROR: no location provided\n"); - fprintf(stderr, "Usage: ADM_define_data_operation \n"); + test_info_t test_info = { + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + cli_args_t cli_args; + if(process_args(argc, argv, test_info, &cli_args)) { exit(EXIT_FAILURE); } int exit_status = EXIT_SUCCESS; - ADM_server_t server = ADM_server_create("tcp", argv[1]); + ADM_server_t server = ADM_server_create("tcp", cli_args.server_address); ADM_job_t job = NULL; ADM_node_t* job_nodes = prepare_nodes(NJOB_NODES); @@ -65,7 +70,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, + ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_deploy_adhoc_storage.c b/examples/c/ADM_deploy_adhoc_storage.c index 1dc7c0359a8b267da272b1ecb5ed427be34b673d..4d6d91dd6fe184808aeaba98ce91ea03665c76c7 100644 --- a/examples/c/ADM_deploy_adhoc_storage.c +++ b/examples/c/ADM_deploy_adhoc_storage.c @@ -34,9 +34,14 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fprintf(stderr, "ERROR: no location provided\n"); - fprintf(stderr, "Usage: ADM_deploy_adhoc_storage \n"); + test_info_t test_info = { + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + cli_args_t cli_args; + if(process_args(argc, argv, test_info, &cli_args)) { exit(EXIT_FAILURE); } @@ -76,7 +81,8 @@ main(int argc, char* argv[]) { } // 3. the adhoc storage execution context - adhoc_ctx = ADM_adhoc_context_create(ADM_ADHOC_MODE_SEPARATE_NEW, + adhoc_ctx = ADM_adhoc_context_create(cli_args.controller_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); if(adhoc_ctx == NULL) { @@ -89,7 +95,7 @@ main(int argc, char* argv[]) { // now ready. Let's actually contact the server: // 1. Find the server endpoint - if((server = ADM_server_create("tcp", argv[1])) == NULL) { + if((server = ADM_server_create("tcp", cli_args.server_address)) == NULL) { fprintf(stderr, "Fatal error creating server\n"); goto cleanup; } @@ -108,7 +114,8 @@ main(int argc, char* argv[]) { // system, let's prepare a new execution context for the adhoc // storage system - new_adhoc_ctx = ADM_adhoc_context_create(ADM_ADHOC_MODE_SEPARATE_NEW, + new_adhoc_ctx = ADM_adhoc_context_create(cli_args.controller_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 200, false); if(new_adhoc_ctx == NULL) { diff --git a/examples/c/ADM_finalize_data_operation.c b/examples/c/ADM_finalize_data_operation.c index 9851326ec8e4333f976b34b334b59401d2cee9b1..89c421ea1c78e51ab66f1141a0a4e570c283236e 100644 --- a/examples/c/ADM_finalize_data_operation.c +++ b/examples/c/ADM_finalize_data_operation.c @@ -36,15 +36,19 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fprintf(stderr, "ERROR: no location provided\n"); - fprintf(stderr, - "Usage: ADM_finalize_data_operation \n"); + test_info_t test_info = { + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + cli_args_t cli_args; + if(process_args(argc, argv, test_info, &cli_args)) { exit(EXIT_FAILURE); } int exit_status = EXIT_SUCCESS; - ADM_server_t server = ADM_server_create("tcp", argv[1]); + ADM_server_t server = ADM_server_create("tcp", cli_args.server_address); ADM_job_t job = NULL; ADM_node_t* job_nodes = prepare_nodes(NJOB_NODES); @@ -61,7 +65,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, + ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_get_pending_transfers.c b/examples/c/ADM_get_pending_transfers.c index e2c109bf7d75360e2801e16195cf5d65674b50e1..6789136cf19e5018d395e82067fe8df395f80feb 100644 --- a/examples/c/ADM_get_pending_transfers.c +++ b/examples/c/ADM_get_pending_transfers.c @@ -36,14 +36,19 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fprintf(stderr, "ERROR: no location provided\n"); - fprintf(stderr, "Usage: ADM_get_pending_transfers \n"); + test_info_t test_info = { + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + cli_args_t cli_args; + if(process_args(argc, argv, test_info, &cli_args)) { exit(EXIT_FAILURE); } int exit_status = EXIT_SUCCESS; - ADM_server_t server = ADM_server_create("tcp", argv[1]); + ADM_server_t server = ADM_server_create("tcp", cli_args.server_address); ADM_job_t job = NULL; ADM_node_t* job_nodes = prepare_nodes(NJOB_NODES); @@ -64,7 +69,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, + ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_get_qos_constraints.c b/examples/c/ADM_get_qos_constraints.c index 6644c99ba1e1213e64f61dd05637afb90b5ea8d1..be8498ee58579ce6312c60101a29f936146d1cc3 100644 --- a/examples/c/ADM_get_qos_constraints.c +++ b/examples/c/ADM_get_qos_constraints.c @@ -36,14 +36,19 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fprintf(stderr, "ERROR: no location provided\n"); - fprintf(stderr, "Usage: ADM_get_qos_constraints \n"); + test_info_t test_info = { + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + cli_args_t cli_args; + if(process_args(argc, argv, test_info, &cli_args)) { exit(EXIT_FAILURE); } int exit_status = EXIT_SUCCESS; - ADM_server_t server = ADM_server_create("tcp", argv[1]); + ADM_server_t server = ADM_server_create("tcp", cli_args.server_address); ADM_job_t job = NULL; ADM_node_t* job_nodes = prepare_nodes(NJOB_NODES); @@ -60,7 +65,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, + ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_get_statistics.c b/examples/c/ADM_get_statistics.c index 9686246bb2a270854e293c3b83d5df982723edd3..4f0c7db51a95a18898b27b71aa4eea33039328f5 100644 --- a/examples/c/ADM_get_statistics.c +++ b/examples/c/ADM_get_statistics.c @@ -36,14 +36,19 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fprintf(stderr, "ERROR: no location provided\n"); - fprintf(stderr, "Usage: ADM_get_statistics \n"); + test_info_t test_info = { + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + cli_args_t cli_args; + if(process_args(argc, argv, test_info, &cli_args)) { exit(EXIT_FAILURE); } int exit_status = EXIT_SUCCESS; - ADM_server_t server = ADM_server_create("tcp", argv[1]); + ADM_server_t server = ADM_server_create("tcp", cli_args.server_address); ADM_job_t job = NULL; ADM_node_t* job_nodes = prepare_nodes(NJOB_NODES); @@ -60,7 +65,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, + ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_get_transfer_priority.c b/examples/c/ADM_get_transfer_priority.c index 2be2ac0f277a9bb9512fc83048d41ac7b62cbf11..5a5957bdeb46646c39045ec455a06d4b3ecd4008 100644 --- a/examples/c/ADM_get_transfer_priority.c +++ b/examples/c/ADM_get_transfer_priority.c @@ -36,14 +36,19 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fprintf(stderr, "ERROR: no location provided\n"); - fprintf(stderr, "Usage: ADM_get_transfer_priority \n"); + test_info_t test_info = { + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + cli_args_t cli_args; + if(process_args(argc, argv, test_info, &cli_args)) { exit(EXIT_FAILURE); } int exit_status = EXIT_SUCCESS; - ADM_server_t server = ADM_server_create("tcp", argv[1]); + ADM_server_t server = ADM_server_create("tcp", cli_args.server_address); ADM_job_t job = NULL; ADM_node_t* job_nodes = prepare_nodes(NJOB_NODES); @@ -64,7 +69,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, + ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_link_transfer_to_data_operation.c b/examples/c/ADM_link_transfer_to_data_operation.c index 66bd656b3854a7bbe5df86f6cee9a0c3c3aac7ee..bfab8b6b1098e511859f9b2567d430fbe01ecb4e 100644 --- a/examples/c/ADM_link_transfer_to_data_operation.c +++ b/examples/c/ADM_link_transfer_to_data_operation.c @@ -36,15 +36,19 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fprintf(stderr, "ERROR: no location provided\n"); - fprintf(stderr, - "Usage: ADM_link_transfer_to_data_operation \n"); + test_info_t test_info = { + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + cli_args_t cli_args; + if(process_args(argc, argv, test_info, &cli_args)) { exit(EXIT_FAILURE); } int exit_status = EXIT_SUCCESS; - ADM_server_t server = ADM_server_create("tcp", argv[1]); + ADM_server_t server = ADM_server_create("tcp", cli_args.server_address); ADM_job_t job = NULL; ADM_node_t* job_nodes = prepare_nodes(NJOB_NODES); @@ -61,7 +65,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, + ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_ping.c b/examples/c/ADM_ping.c index a197642f7dcf986d8844f701c1df73609ffee507..7ec297200bc0726a8640088e6fbbbe8cd896f127 100644 --- a/examples/c/ADM_ping.c +++ b/examples/c/ADM_ping.c @@ -26,17 +26,23 @@ #include #include #include +#include "common.h" int main(int argc, char* argv[]) { - if(argc != 2) { - fprintf(stderr, "ERROR: no location provided\n"); - fprintf(stderr, "Usage: ADM_ping \n"); + test_info_t test_info = { + .name = TESTNAME, + .requires_server = true, + .requires_controller = false, + }; + + cli_args_t cli_args; + if(process_args(argc, argv, test_info, &cli_args)) { exit(EXIT_FAILURE); } - ADM_server_t server = ADM_server_create("tcp", argv[1]); + ADM_server_t server = ADM_server_create("tcp", cli_args.server_address); ADM_return_t ret = ADM_ping(server); diff --git a/examples/c/ADM_register_adhoc_storage.c b/examples/c/ADM_register_adhoc_storage.c index 5f2a86dc3a6caeb6dfb012d02aa6685bebef0b79..0d2ff17e3ac23b331683feec6be8c819dd9b9fec 100644 --- a/examples/c/ADM_register_adhoc_storage.c +++ b/examples/c/ADM_register_adhoc_storage.c @@ -34,9 +34,14 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fprintf(stderr, "ERROR: no location provided\n"); - fprintf(stderr, "Usage: ADM_register_adhoc_storage \n"); + test_info_t test_info = { + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + cli_args_t cli_args; + if(process_args(argc, argv, test_info, &cli_args)) { exit(EXIT_FAILURE); } @@ -73,7 +78,8 @@ main(int argc, char* argv[]) { } // 3. define the adhoc execution context - adhoc_ctx = ADM_adhoc_context_create(ADM_ADHOC_MODE_SEPARATE_NEW, + adhoc_ctx = ADM_adhoc_context_create(cli_args.controller_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); if(adhoc_ctx == NULL) { @@ -85,7 +91,7 @@ main(int argc, char* argv[]) { // now ready. Let's actually contact the server: // 1. Find the server endpoint - if((server = ADM_server_create("tcp", argv[1])) == NULL) { + if((server = ADM_server_create("tcp", cli_args.server_address)) == NULL) { fprintf(stderr, "Fatal error creating server\n"); goto cleanup; } diff --git a/examples/c/ADM_register_job.c b/examples/c/ADM_register_job.c index 36bc1dbb5d9acfd6e69ceb5589c00482584900f2..e4be41538f28117bcaec7e0ad95911a76039e14d 100644 --- a/examples/c/ADM_register_job.c +++ b/examples/c/ADM_register_job.c @@ -35,9 +35,14 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fprintf(stderr, "ERROR: no location provided\n"); - fprintf(stderr, "Usage: ADM_register_job \n"); + test_info_t test_info = { + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + cli_args_t cli_args; + if(process_args(argc, argv, test_info, &cli_args)) { exit(EXIT_FAILURE); } @@ -83,7 +88,8 @@ main(int argc, char* argv[]) { } // 3. the adhoc storage execution context - adhoc_ctx = ADM_adhoc_context_create(ADM_ADHOC_MODE_SEPARATE_NEW, + adhoc_ctx = ADM_adhoc_context_create(cli_args.controller_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); if(adhoc_ctx == NULL) { @@ -96,15 +102,15 @@ main(int argc, char* argv[]) { // now ready. Let's actually contact the server: // 1. Find the server endpoint - if((server = ADM_server_create("tcp", argv[1])) == NULL) { + if((server = ADM_server_create("tcp", cli_args.server_address)) == NULL) { fprintf(stderr, "Fatal error creating server\n"); goto cleanup; } // 2. Register the adhoc storage - if(ADM_register_adhoc_storage(server, adhoc_name, ADM_ADHOC_STORAGE_GEKKOFS, - adhoc_ctx, adhoc_resources, - &adhoc_storage) != ADM_SUCCESS) { + if((ret = ADM_register_adhoc_storage( + server, adhoc_name, ADM_ADHOC_STORAGE_GEKKOFS, adhoc_ctx, + adhoc_resources, &adhoc_storage)) != ADM_SUCCESS) { fprintf(stderr, "ADM_register_adhoc_storage() failed: %s\n", ADM_strerror(ret)); goto cleanup; @@ -154,8 +160,8 @@ main(int argc, char* argv[]) { // All the information required by the ADM_register_job() API is now ready. // Let's actually contact the server: - if(ADM_register_job(server, job_resources, reqs, slurm_job_id, &job) != - ADM_SUCCESS) { + if((ret = ADM_register_job(server, job_resources, reqs, slurm_job_id, + &job)) != ADM_SUCCESS) { fprintf(stderr, "ADM_register_job() failed: %s\n", ADM_strerror(ret)); goto cleanup; } diff --git a/examples/c/ADM_register_pfs_storage.c b/examples/c/ADM_register_pfs_storage.c index 8510bfc373e721776595a58525a68cee7e9d6962..5c7ecc2fdfcb657591cd7f7fa385755e253a2357 100644 --- a/examples/c/ADM_register_pfs_storage.c +++ b/examples/c/ADM_register_pfs_storage.c @@ -25,13 +25,19 @@ #include #include #include +#include "common.h" int main(int argc, char* argv[]) { - if(argc != 2) { - fprintf(stderr, "ERROR: no server address provided\n"); - fprintf(stderr, "Usage: ADM_register_pfs_storage \n"); + test_info_t test_info = { + .name = TESTNAME, + .requires_server = true, + .requires_controller = false, + }; + + cli_args_t cli_args; + if(process_args(argc, argv, test_info, &cli_args)) { exit(EXIT_FAILURE); } @@ -62,7 +68,7 @@ main(int argc, char* argv[]) { // now ready. Let's actually contact the server: // 1. Find the server endpoint - if((server = ADM_server_create("tcp", argv[1])) == NULL) { + if((server = ADM_server_create("tcp", cli_args.server_address)) == NULL) { fprintf(stderr, "Fatal error creating server\n"); goto cleanup; } diff --git a/examples/c/ADM_remove_adhoc_storage.c b/examples/c/ADM_remove_adhoc_storage.c index 23e404bb596759944af91e9c8467375bd77c4294..17d8cf78292b611b48f94fbe0a2ed2566e740c1b 100644 --- a/examples/c/ADM_remove_adhoc_storage.c +++ b/examples/c/ADM_remove_adhoc_storage.c @@ -34,9 +34,14 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fprintf(stderr, "ERROR: no location provided\n"); - fprintf(stderr, "Usage: ADM_remove_adhoc_storage \n"); + test_info_t test_info = { + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + cli_args_t cli_args; + if(process_args(argc, argv, test_info, &cli_args)) { exit(EXIT_FAILURE); } @@ -75,7 +80,8 @@ main(int argc, char* argv[]) { } // 3. the adhoc storage execution context - adhoc_ctx = ADM_adhoc_context_create(ADM_ADHOC_MODE_SEPARATE_NEW, + adhoc_ctx = ADM_adhoc_context_create(cli_args.controller_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); if(adhoc_ctx == NULL) { @@ -88,7 +94,7 @@ main(int argc, char* argv[]) { // now ready. Let's actually contact the server: // 1. Find the server endpoint - if((server = ADM_server_create("tcp", argv[1])) == NULL) { + if((server = ADM_server_create("tcp", cli_args.server_address)) == NULL) { fprintf(stderr, "Fatal error creating server\n"); goto cleanup; } diff --git a/examples/c/ADM_remove_job.c b/examples/c/ADM_remove_job.c index c4d0a7c887d949f1a6c7114599dd7489bc9f5330..ddf7a2d6f2064df0241c056c767b485e16ba55dc 100644 --- a/examples/c/ADM_remove_job.c +++ b/examples/c/ADM_remove_job.c @@ -36,14 +36,19 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fprintf(stderr, "ERROR: no location provided\n"); - fprintf(stderr, "Usage: ADM_remove_job \n"); + test_info_t test_info = { + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + cli_args_t cli_args; + if(process_args(argc, argv, test_info, &cli_args)) { exit(EXIT_FAILURE); } int exit_status = EXIT_SUCCESS; - ADM_server_t server = ADM_server_create("tcp", argv[1]); + ADM_server_t server = ADM_server_create("tcp", cli_args.server_address); ADM_job_t job = NULL; ADM_node_t* job_nodes = prepare_nodes(NJOB_NODES); @@ -64,7 +69,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, + ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_remove_pfs_storage.c b/examples/c/ADM_remove_pfs_storage.c index d2bc0017e46b406062a4167a0c50c838c6df329b..34423b8e645b944722872674d01cee1369b5d1f3 100644 --- a/examples/c/ADM_remove_pfs_storage.c +++ b/examples/c/ADM_remove_pfs_storage.c @@ -18,7 +18,9 @@ * * You should have received a copy of the GNU General Public License * along with scord. If not, see . - * + if(test_info.requires_server) { + } +* * SPDX-License-Identifier: GPL-3.0-or-later *****************************************************************************/ @@ -26,13 +28,19 @@ #include #include #include +#include "common.h" int main(int argc, char* argv[]) { - if(argc != 2) { - fprintf(stderr, "ERROR: no server address provided\n"); - fprintf(stderr, "Usage: ADM_remove_pfs_storage \n"); + test_info_t test_info = { + .name = TESTNAME, + .requires_server = true, + .requires_controller = false, + }; + + cli_args_t cli_args; + if(process_args(argc, argv, test_info, &cli_args)) { exit(EXIT_FAILURE); } @@ -63,7 +71,7 @@ main(int argc, char* argv[]) { // now ready. Let's actually contact the server: // 1. Find the server endpoint - if((server = ADM_server_create("tcp", argv[1])) == NULL) { + if((server = ADM_server_create("tcp", cli_args.server_address)) == NULL) { fprintf(stderr, "Fatal error creating server\n"); goto cleanup; } diff --git a/examples/c/ADM_set_dataset_information.c b/examples/c/ADM_set_dataset_information.c index ddeefe0cf235080cb87a1f24d901b68e1aceac6e..548befd80a4773c717dcff6645cf35455784dee3 100644 --- a/examples/c/ADM_set_dataset_information.c +++ b/examples/c/ADM_set_dataset_information.c @@ -36,15 +36,19 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fprintf(stderr, "ERROR: no location provided\n"); - fprintf(stderr, - "Usage: ADM_set_dataset_information \n"); + test_info_t test_info = { + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + cli_args_t cli_args; + if(process_args(argc, argv, test_info, &cli_args)) { exit(EXIT_FAILURE); } int exit_status = EXIT_SUCCESS; - ADM_server_t server = ADM_server_create("tcp", argv[1]); + ADM_server_t server = ADM_server_create("tcp", cli_args.server_address); ADM_job_t job = NULL; ADM_node_t* job_nodes = prepare_nodes(NJOB_NODES); @@ -61,7 +65,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, + ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_set_io_resources.c b/examples/c/ADM_set_io_resources.c index 37989fa5b6056b76118a525b0046345e650f5a18..cdf07a3bbefc20c5f840cb60522bf980ad37ee77 100644 --- a/examples/c/ADM_set_io_resources.c +++ b/examples/c/ADM_set_io_resources.c @@ -36,14 +36,19 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fprintf(stderr, "ERROR: no location provided\n"); - fprintf(stderr, "Usage: ADM_set_io_resources \n"); + test_info_t test_info = { + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + cli_args_t cli_args; + if(process_args(argc, argv, test_info, &cli_args)) { exit(EXIT_FAILURE); } int exit_status = EXIT_SUCCESS; - ADM_server_t server = ADM_server_create("tcp", argv[1]); + ADM_server_t server = ADM_server_create("tcp", cli_args.server_address); ADM_job_t job = NULL; ADM_node_t* job_nodes = prepare_nodes(NJOB_NODES); @@ -60,7 +65,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, + ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_set_qos_constraints.c b/examples/c/ADM_set_qos_constraints.c index dec01f69424b0795655198b2e0f9c3678c8879a7..a7f07bc11165cafae34ad9b1fff07328e0019b15 100644 --- a/examples/c/ADM_set_qos_constraints.c +++ b/examples/c/ADM_set_qos_constraints.c @@ -36,14 +36,19 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fprintf(stderr, "ERROR: no location provided\n"); - fprintf(stderr, "Usage: ADM_set_qos_constraints \n"); + test_info_t test_info = { + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + cli_args_t cli_args; + if(process_args(argc, argv, test_info, &cli_args)) { exit(EXIT_FAILURE); } int exit_status = EXIT_SUCCESS; - ADM_server_t server = ADM_server_create("tcp", argv[1]); + ADM_server_t server = ADM_server_create("tcp", cli_args.server_address); ADM_job_t job = NULL; ADM_node_t* job_nodes = prepare_nodes(NJOB_NODES); @@ -64,7 +69,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, + ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_set_transfer_priority.c b/examples/c/ADM_set_transfer_priority.c index 60e33761c5f888bb5a6d181a51fb04b5ce7903fc..8ba26be5909a38059d6f4e5377b8016b8b645af8 100644 --- a/examples/c/ADM_set_transfer_priority.c +++ b/examples/c/ADM_set_transfer_priority.c @@ -36,14 +36,19 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fprintf(stderr, "ERROR: no location provided\n"); - fprintf(stderr, "Usage: ADM_set_transfer_priority \n"); + test_info_t test_info = { + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + cli_args_t cli_args; + if(process_args(argc, argv, test_info, &cli_args)) { exit(EXIT_FAILURE); } int exit_status = EXIT_SUCCESS; - ADM_server_t server = ADM_server_create("tcp", argv[1]); + ADM_server_t server = ADM_server_create("tcp", cli_args.server_address); ADM_job_t job = NULL; ADM_node_t* job_nodes = prepare_nodes(NJOB_NODES); @@ -64,7 +69,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, + ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_tear_down_adhoc_storage.c b/examples/c/ADM_tear_down_adhoc_storage.c index 10e6546c46c279b03fc29f7fdd4e7493066a3d99..996d03e13246eb38ed70ec0cb8314c0a7d594e4c 100644 --- a/examples/c/ADM_tear_down_adhoc_storage.c +++ b/examples/c/ADM_tear_down_adhoc_storage.c @@ -34,9 +34,14 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fprintf(stderr, "ERROR: no location provided\n"); - fprintf(stderr, "Usage: ADM_deploy_adhoc_storage \n"); + test_info_t test_info = { + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + cli_args_t cli_args; + if(process_args(argc, argv, test_info, &cli_args)) { exit(EXIT_FAILURE); } @@ -76,7 +81,8 @@ main(int argc, char* argv[]) { } // 3. the adhoc storage execution context - adhoc_ctx = ADM_adhoc_context_create(ADM_ADHOC_MODE_SEPARATE_NEW, + adhoc_ctx = ADM_adhoc_context_create(cli_args.controller_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); if(adhoc_ctx == NULL) { @@ -89,7 +95,7 @@ main(int argc, char* argv[]) { // now ready. Let's actually contact the server: // 1. Find the server endpoint - if((server = ADM_server_create("tcp", argv[1])) == NULL) { + if((server = ADM_server_create("tcp", cli_args.server_address)) == NULL) { fprintf(stderr, "Fatal error creating server\n"); goto cleanup; } @@ -108,7 +114,8 @@ main(int argc, char* argv[]) { // system, let's prepare a new execution context for the adhoc // storage system - new_adhoc_ctx = ADM_adhoc_context_create(ADM_ADHOC_MODE_SEPARATE_NEW, + new_adhoc_ctx = ADM_adhoc_context_create(cli_args.controller_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 200, false); if(new_adhoc_ctx == NULL) { diff --git a/examples/c/ADM_transfer_datasets.c b/examples/c/ADM_transfer_datasets.c index 73af36c5e14e7c80bc9f5f3b355a0579df1869cc..343c603e223ae667938eed9b86808488ec65d82a 100644 --- a/examples/c/ADM_transfer_datasets.c +++ b/examples/c/ADM_transfer_datasets.c @@ -39,14 +39,19 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fprintf(stderr, "ERROR: no location provided\n"); - fprintf(stderr, "Usage: ADM_transfer_datasets \n"); + test_info_t test_info = { + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + cli_args_t cli_args; + if(process_args(argc, argv, test_info, &cli_args)) { exit(EXIT_FAILURE); } int exit_status = EXIT_SUCCESS; - ADM_server_t server = ADM_server_create("tcp", argv[1]); + ADM_server_t server = ADM_server_create("tcp", cli_args.server_address); ADM_job_t job = NULL; ADM_node_t* job_nodes = prepare_nodes(NJOB_NODES); @@ -67,7 +72,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, + ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_update_adhoc_storage.c b/examples/c/ADM_update_adhoc_storage.c index f8f063979cdebf9fd480752b3798fabeb0b72a0c..823f5504ef32b92dffcc1ae6f4489effbcb41e6a 100644 --- a/examples/c/ADM_update_adhoc_storage.c +++ b/examples/c/ADM_update_adhoc_storage.c @@ -35,9 +35,14 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fprintf(stderr, "ERROR: no location provided\n"); - fprintf(stderr, "Usage: ADM_update_adhoc_storage \n"); + test_info_t test_info = { + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + cli_args_t cli_args; + if(process_args(argc, argv, test_info, &cli_args)) { exit(EXIT_FAILURE); } @@ -79,7 +84,8 @@ main(int argc, char* argv[]) { } // 3. the adhoc storage execution context - adhoc_ctx = ADM_adhoc_context_create(ADM_ADHOC_MODE_SEPARATE_NEW, + adhoc_ctx = ADM_adhoc_context_create(cli_args.controller_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); if(adhoc_ctx == NULL) { @@ -92,7 +98,7 @@ main(int argc, char* argv[]) { // now ready. Let's actually contact the server: // 1. Find the server endpoint - if((server = ADM_server_create("tcp", argv[1])) == NULL) { + if((server = ADM_server_create("tcp", cli_args.server_address)) == NULL) { fprintf(stderr, "Fatal error creating server\n"); goto cleanup; } @@ -118,7 +124,8 @@ main(int argc, char* argv[]) { goto cleanup; } - new_adhoc_ctx = ADM_adhoc_context_create(ADM_ADHOC_MODE_SEPARATE_NEW, + new_adhoc_ctx = ADM_adhoc_context_create(cli_args.controller_address, + ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 200, false); if(new_adhoc_ctx == NULL) { diff --git a/examples/c/ADM_update_job.c b/examples/c/ADM_update_job.c index 2e94ddedb7fe255fe007ea11c90776b8636dfece..25ca673525c4455c0438cbfa9498bb6b9c6cf5d7 100644 --- a/examples/c/ADM_update_job.c +++ b/examples/c/ADM_update_job.c @@ -36,14 +36,19 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fprintf(stderr, "ERROR: no location provided\n"); - fprintf(stderr, "Usage: ADM_update_job \n"); + test_info_t test_info = { + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + cli_args_t cli_args; + if(process_args(argc, argv, test_info, &cli_args)) { exit(EXIT_FAILURE); } int exit_status = EXIT_SUCCESS; - ADM_server_t server = ADM_server_create("tcp", argv[1]); + ADM_server_t server = ADM_server_create("tcp", cli_args.server_address); ADM_job_t job; ADM_node_t* job_nodes = prepare_nodes(NJOB_NODES); @@ -64,7 +69,8 @@ main(int argc, char* argv[]) { assert(adhoc_resources); ADM_adhoc_context_t ctx = ADM_adhoc_context_create( - ADM_ADHOC_MODE_SEPARATE_NEW, ADM_ADHOC_ACCESS_RDWR, 100, false); + cli_args.controller_address, ADM_ADHOC_MODE_SEPARATE_NEW, + ADM_ADHOC_ACCESS_RDWR, 100, false); assert(ctx); const char* name = "adhoc_storage_42"; diff --git a/examples/c/ADM_update_pfs_storage.c b/examples/c/ADM_update_pfs_storage.c index 95aea01cdf943cb98d4eb5e1cb51609896dba29d..dce5f27e5e67e0d38fbd31c3f3884fb75525158c 100644 --- a/examples/c/ADM_update_pfs_storage.c +++ b/examples/c/ADM_update_pfs_storage.c @@ -26,13 +26,19 @@ #include #include #include +#include "common.h" int main(int argc, char* argv[]) { - if(argc != 2) { - fprintf(stderr, "ERROR: no server address provided\n"); - fprintf(stderr, "Usage: ADM_update_pfs_storage \n"); + test_info_t test_info = { + .name = TESTNAME, + .requires_server = true, + .requires_controller = false, + }; + + cli_args_t cli_args; + if(process_args(argc, argv, test_info, &cli_args)) { exit(EXIT_FAILURE); } @@ -65,7 +71,7 @@ main(int argc, char* argv[]) { // now ready. Let's actually contact the server: // 1. Find the server endpoint - if((server = ADM_server_create("tcp", argv[1])) == NULL) { + if((server = ADM_server_create("tcp", cli_args.server_address)) == NULL) { fprintf(stderr, "Fatal error creating server\n"); goto cleanup; } diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt index ce29ffbdc3845c92ff2102ce4c67569cb1acac09..cbc590b510871def113b785367dbb70a6c67ea43 100644 --- a/examples/c/CMakeLists.txt +++ b/examples/c/CMakeLists.txt @@ -22,16 +22,12 @@ # SPDX-License-Identifier: GPL-3.0-or-later # ################################################################################ -list(APPEND examples_c - # ping - ADM_ping +list(APPEND c_examples_with_controller # job ADM_register_job ADM_update_job ADM_remove_job # adhoc storage ADM_register_adhoc_storage ADM_update_adhoc_storage ADM_remove_adhoc_storage ADM_deploy_adhoc_storage ADM_tear_down_adhoc_storage - # pfs storage - ADM_register_pfs_storage ADM_update_pfs_storage ADM_remove_pfs_storage # transfers ADM_transfer_datasets ADM_get_transfer_priority ADM_set_transfer_priority ADM_cancel_transfer ADM_get_pending_transfers @@ -45,11 +41,18 @@ list(APPEND examples_c ADM_get_statistics ADM_set_dataset_information ADM_set_io_resources ) +list(APPEND c_examples_without_controller + # ping + ADM_ping + # pfs storage + ADM_register_pfs_storage ADM_update_pfs_storage ADM_remove_pfs_storage + ) + add_library(c_examples_common STATIC) target_sources(c_examples_common PUBLIC common.h PRIVATE common.c) target_link_libraries(c_examples_common libscord_c_types) -foreach(example IN LISTS examples_c) +foreach(example IN LISTS c_examples_with_controller c_examples_without_controller) add_executable(${example}_c) target_sources(${example}_c PRIVATE ${example}.c) target_link_libraries(${example}_c PUBLIC libscord c_examples_common) @@ -57,7 +60,7 @@ foreach(example IN LISTS examples_c) endforeach() if(SCORD_BUILD_TESTS) - foreach(example IN LISTS examples_c) + foreach(example IN LISTS c_examples_with_controller) # prepare environment for the RPC test itself and its validation test set(TEST_NAME "${example}_c_test") @@ -69,16 +72,48 @@ if(SCORD_BUILD_TESTS) list(APPEND TEST_ENV LIBSCORD_LOG_OUTPUT=${TEST_DIRECTORY}/libscord.log) add_test(run_${TEST_NAME} ${example} - ${SCORD_TRANSPORT_PROTOCOL}://${SCORD_BIND_ADDRESS}:${SCORD_BIND_PORT}) + ${SCORD_ADDRESS_STRING} + ${SCORD_CTL_ADDRESS_STRING}) set_tests_properties(run_${TEST_NAME} - PROPERTIES FIXTURES_REQUIRED scord_daemon + PROPERTIES FIXTURES_REQUIRED "scord_daemon;scord_ctl" ENVIRONMENT "${TEST_ENV}") add_test(validate_${TEST_NAME} ${CMAKE_SOURCE_DIR}/ci/check_rpcs.py + ${example} ${TEST_DIRECTORY}/libscord.log ${SCORD_TESTS_DIRECTORY}/scord_daemon/scord_daemon.log + ${SCORD_ADDRESS_STRING} + ${SCORD_TESTS_DIRECTORY}/scord_daemon/scord_ctl.log + ${SCORD_CTL_ADDRESS_STRING} + ) + set_tests_properties(validate_${TEST_NAME} + PROPERTIES DEPENDS stop_scord_daemon + ) + endforeach() + + foreach(example IN LISTS c_examples_without_controller) + + # prepare environment for the RPC test itself and its validation test + set(TEST_NAME "${example}_c_test") + set(TEST_DIRECTORY "${SCORD_TESTS_DIRECTORY}/${TEST_NAME}") + file(MAKE_DIRECTORY ${TEST_DIRECTORY}) + + set(TEST_ENV) + list(APPEND TEST_ENV LIBSCORD_LOG=1) + list(APPEND TEST_ENV LIBSCORD_LOG_OUTPUT=${TEST_DIRECTORY}/libscord.log) + + add_test(run_${TEST_NAME} ${example} ${SCORD_ADDRESS_STRING}) + set_tests_properties(run_${TEST_NAME} + PROPERTIES FIXTURES_REQUIRED scord_daemon + ENVIRONMENT "${TEST_ENV}") + + add_test(validate_${TEST_NAME} + ${CMAKE_SOURCE_DIR}/ci/check_rpcs.py ${example} + ${TEST_DIRECTORY}/libscord.log + ${SCORD_TESTS_DIRECTORY}/scord_daemon/scord_daemon.log + ${SCORD_ADDRESS_STRING} ) set_tests_properties(validate_${TEST_NAME} PROPERTIES DEPENDS stop_scord_daemon diff --git a/examples/c/common.c b/examples/c/common.c index c5b97ae499228e8edf5b5aacd02f2a852b349389..b19935986c31a73fde8798e65a0b0d2e660fa8a0 100644 --- a/examples/c/common.c +++ b/examples/c/common.c @@ -2,8 +2,37 @@ #define SCORD_COMMON_H #include +#include #include "common.h" +int +process_args(int argc, char* argv[], test_info_t test_info, cli_args_t* args) { + + int required_args = 1; + + if(test_info.requires_server) { + ++required_args; + } + + if(test_info.requires_controller) { + ++required_args; + } + + if(argc != required_args) { + fprintf(stderr, "ERROR: missing arguments\n"); + fprintf(stderr, "Usage: %s%s%s\n", test_info.name, + test_info.requires_server ? " " : "", + test_info.requires_controller ? " " : ""); + return -1; + } + + args->server_address = test_info.requires_server ? argv[1] : NULL; + args->controller_address = test_info.requires_controller ? argv[2] : NULL; + + return 0; +} + + ADM_node_t* prepare_nodes(size_t n) { diff --git a/examples/c/common.h b/examples/c/common.h index 0aeab9c92e388c8e0c8fb52b176e413053a7b193..53d472113ab6c0e1d831319f0979adb99fd4001a 100644 --- a/examples/c/common.h +++ b/examples/c/common.h @@ -3,6 +3,24 @@ #include +#define TESTNAME \ + (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 \ + : __FILE__) + +typedef struct { + const char* name; + bool requires_server; + bool requires_controller; +} test_info_t; + +typedef struct { + const char* server_address; + const char* controller_address; +} cli_args_t; + +int +process_args(int argc, char* argv[], test_info_t test_info, cli_args_t* args); + ADM_node_t* prepare_nodes(size_t n); diff --git a/examples/cxx/ADM_cancel_transfer.cpp b/examples/cxx/ADM_cancel_transfer.cpp index 1abff9ca24d7511e339a18f477dac2b87b5cbe6e..d2791147037f6c826c404c9f8e470d93b8a81a8e 100644 --- a/examples/cxx/ADM_cancel_transfer.cpp +++ b/examples/cxx/ADM_cancel_transfer.cpp @@ -24,18 +24,20 @@ #include #include - +#include "common.hpp" int main(int argc, char* argv[]) { - if(argc != 2) { - fmt::print(stderr, "ERROR: no location provided\n"); - fmt::print(stderr, "Usage: ADM_cancel_transfer \n"); - exit(EXIT_FAILURE); - } + test_info test_info{ + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + const auto cli_args = process_args(argc, argv, test_info); - scord::server server{"tcp", argv[1]}; + scord::server server{"tcp", cli_args.server_address}; ADM_job_t job{}; ADM_transfer_t tx{}; diff --git a/examples/cxx/ADM_connect_data_operation.cpp b/examples/cxx/ADM_connect_data_operation.cpp index 5ff68267834cfa56691f29726ea60650ed96882b..d3bc9ac1d63c15841e4cea875d81ff3b7a5d1176 100644 --- a/examples/cxx/ADM_connect_data_operation.cpp +++ b/examples/cxx/ADM_connect_data_operation.cpp @@ -24,18 +24,20 @@ #include #include +#include "common.hpp" int main(int argc, char* argv[]) { - if(argc != 2) { - fmt::print(stderr, "ERROR: no location provided\n"); - fmt::print(stderr, - "Usage: ADM_connect_data_operation \n"); - exit(EXIT_FAILURE); - } + test_info test_info{ + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + const auto cli_args = process_args(argc, argv, test_info); - scord::server server{"tcp", argv[1]}; + scord::server server{"tcp", cli_args.server_address}; ADM_job_t job{}; ADM_dataset_t input{}; diff --git a/examples/cxx/ADM_define_data_operation.cpp b/examples/cxx/ADM_define_data_operation.cpp index bf087508b244b9daa5de31b5512c954e6b8e8524..e34a8d05568000ab5243c7f1e2c980b756825aef 100644 --- a/examples/cxx/ADM_define_data_operation.cpp +++ b/examples/cxx/ADM_define_data_operation.cpp @@ -24,19 +24,20 @@ #include #include - +#include "common.hpp" int main(int argc, char* argv[]) { - if(argc != 2) { - fmt::print(stderr, "ERROR: no location provided\n"); - fmt::print(stderr, - "Usage: ADM_define_data_operation \n"); - exit(EXIT_FAILURE); - } + test_info test_info{ + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + const auto cli_args = process_args(argc, argv, test_info); - scord::server server{"tcp", argv[1]}; + scord::server server{"tcp", cli_args.server_address}; ADM_job_t job{}; const char* path = "/tmpxxxxx"; diff --git a/examples/cxx/ADM_deploy_adhoc_storage.cpp b/examples/cxx/ADM_deploy_adhoc_storage.cpp index 38077ccaad2cab36c369f2f90278abf901860059..ac37c49fac9f3088d15d30c2f5265d659cc388b3 100644 --- a/examples/cxx/ADM_deploy_adhoc_storage.cpp +++ b/examples/cxx/ADM_deploy_adhoc_storage.cpp @@ -34,14 +34,15 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fmt::print(stderr, "ERROR: no location provided\n"); - fmt::print(stderr, - "Usage: ADM_deploy_adhoc_storage \n"); - exit(EXIT_FAILURE); - } + test_info test_info{ + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + const auto cli_args = process_args(argc, argv, test_info); - scord::server server{"tcp", argv[1]}; + scord::server server{"tcp", cli_args.server_address}; const auto adhoc_nodes = prepare_nodes(NADHOC_NODES); const auto inputs = prepare_datasets("input-dataset-{}", NINPUTS); @@ -49,6 +50,7 @@ main(int argc, char* argv[]) { std::string name = "adhoc_storage_42"; const auto adhoc_storage_ctx = scord::adhoc_storage::ctx{ + cli_args.controller_address, scord::adhoc_storage::execution_mode::separate_new, scord::adhoc_storage::access_type::read_write, 100, false}; const auto adhoc_resources = scord::adhoc_storage::resources{adhoc_nodes}; diff --git a/examples/cxx/ADM_finalize_data_operation.cpp b/examples/cxx/ADM_finalize_data_operation.cpp index 147ae68664c1ed78b57dc2b50dde2258181b125b..a9148a199b83d1d589412b3a1f612b0bac99a588 100644 --- a/examples/cxx/ADM_finalize_data_operation.cpp +++ b/examples/cxx/ADM_finalize_data_operation.cpp @@ -24,18 +24,20 @@ #include #include +#include "common.hpp" int main(int argc, char* argv[]) { - if(argc != 2) { - fmt::print(stderr, "ERROR: no location provided\n"); - fmt::print(stderr, - "Usage: ADM_finalize_data_operation \n"); - exit(EXIT_FAILURE); - } + test_info test_info{ + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + const auto cli_args = process_args(argc, argv, test_info); - scord::server server{"tcp", argv[1]}; + scord::server server{"tcp", cli_args.server_address}; ADM_job_t job{}; ADM_data_operation_t op{}; diff --git a/examples/cxx/ADM_get_pending_transfers.cpp b/examples/cxx/ADM_get_pending_transfers.cpp index f60be4b2ead9e643624e7732564464c557417fce..60f7d9eb7976f33614b0d2ad16798050016204ed 100644 --- a/examples/cxx/ADM_get_pending_transfers.cpp +++ b/examples/cxx/ADM_get_pending_transfers.cpp @@ -24,19 +24,20 @@ #include #include - +#include "common.hpp" int main(int argc, char* argv[]) { - if(argc != 2) { - fmt::print(stderr, "ERROR: no location provided\n"); - fmt::print(stderr, - "Usage: ADM_get_pending_transfers \n"); - exit(EXIT_FAILURE); - } + test_info test_info{ + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + const auto cli_args = process_args(argc, argv, test_info); - scord::server server{"tcp", argv[1]}; + scord::server server{"tcp", cli_args.server_address}; ADM_job_t job{}; ADM_transfer_t** tx = nullptr; diff --git a/examples/cxx/ADM_get_qos_constraints.cpp b/examples/cxx/ADM_get_qos_constraints.cpp index ba34766c8e117e37cf806888f8ebb16e25087f62..389ac2b199d14312b396c109f156eb1e8bf2ad26 100644 --- a/examples/cxx/ADM_get_qos_constraints.cpp +++ b/examples/cxx/ADM_get_qos_constraints.cpp @@ -24,18 +24,20 @@ #include #include - +#include "common.hpp" int main(int argc, char* argv[]) { - if(argc != 2) { - fmt::print(stderr, "ERROR: no location provided\n"); - fmt::print(stderr, "Usage: ADM_get_qos_constraints \n"); - exit(EXIT_FAILURE); - } + test_info test_info{ + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + const auto cli_args = process_args(argc, argv, test_info); - scord::server server{"tcp", argv[1]}; + scord::server server{"tcp", cli_args.server_address}; ADM_job_t job{}; ADM_qos_entity_t entity{}; diff --git a/examples/cxx/ADM_get_statistics.cpp b/examples/cxx/ADM_get_statistics.cpp index cb8c0cdc720e1779afa9ad275f445cf00ea3d047..a19e506b061a2dd7b21ec8ea9c3f909ad9e06294 100644 --- a/examples/cxx/ADM_get_statistics.cpp +++ b/examples/cxx/ADM_get_statistics.cpp @@ -24,17 +24,20 @@ #include #include +#include "common.hpp" int main(int argc, char* argv[]) { - if(argc != 2) { - fmt::print(stderr, "ERROR: no location provided\n"); - fmt::print(stderr, "Usage: ADM_get_statistics \n"); - exit(EXIT_FAILURE); - } + test_info test_info{ + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + const auto cli_args = process_args(argc, argv, test_info); - scord::server server{"tcp", argv[1]}; + scord::server server{"tcp", cli_args.server_address}; ADM_job_t job{}; ADM_job_stats_t* stats = nullptr; diff --git a/examples/cxx/ADM_get_transfer_priority.cpp b/examples/cxx/ADM_get_transfer_priority.cpp index 7dbd585b91eb93b5f2dcbbed2e721b422debf71d..983c39c18bed25e01368f5744a79f8f91b78c45c 100644 --- a/examples/cxx/ADM_get_transfer_priority.cpp +++ b/examples/cxx/ADM_get_transfer_priority.cpp @@ -24,19 +24,20 @@ #include #include - +#include "common.hpp" int main(int argc, char* argv[]) { - if(argc != 2) { - fmt::print(stderr, "ERROR: no location provided\n"); - fmt::print(stderr, - "Usage: ADM_get_transfer_priority \n"); - exit(EXIT_FAILURE); - } + test_info test_info{ + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + const auto cli_args = process_args(argc, argv, test_info); - scord::server server{"tcp", argv[1]}; + scord::server server{"tcp", cli_args.server_address}; ADM_job_t job{}; ADM_transfer_t tx{}; diff --git a/examples/cxx/ADM_in_situ_ops.cpp b/examples/cxx/ADM_in_situ_ops.cpp index 517b0fd6ae59813ecc1293d0551fadcceea0ad9e..563cf0bc3e1687404580756ba128cb1c50b8f7cf 100644 --- a/examples/cxx/ADM_in_situ_ops.cpp +++ b/examples/cxx/ADM_in_situ_ops.cpp @@ -24,26 +24,28 @@ #include #include - +#include "common.hpp" int main(int argc, char* argv[]) { - if(argc != 2) { - fmt::print(stderr, "ERROR: no location provided\n"); - fmt::print(stderr, "Usage: ADM_in_situ_ops \n"); - exit(EXIT_FAILURE); - } + test_info test_info{ + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + const auto cli_args = process_args(argc, argv, test_info); scord::network::rpc_client rpc_client{"tcp"}; rpc_client.register_rpcs(); - auto endp = rpc_client.lookup(argv[1]); + auto endp = rpc_client.lookup(cli_args.server_address); fmt::print( stdout, "Calling ADM_in_situ_ops remote procedure on {} -> access method: {} ...\n", - argv[1], argv[2]); + cli_args.controller_address, argv[2]); ADM_in_situ_ops_in_t in; in.in_situ = argv[2]; ADM_in_situ_ops_out_t out; diff --git a/examples/cxx/ADM_in_transit_ops.cpp b/examples/cxx/ADM_in_transit_ops.cpp index bf3ce2b054d8abefc31f898ef91542828fccbb19..8e743799f8061f616750707834b5d511ae702de4 100644 --- a/examples/cxx/ADM_in_transit_ops.cpp +++ b/examples/cxx/ADM_in_transit_ops.cpp @@ -24,26 +24,28 @@ #include #include - +#include "common.hpp" int main(int argc, char* argv[]) { - if(argc != 2) { - fmt::print(stderr, "ERROR: no location provided\n"); - fmt::print(stderr, "Usage: ADM_in_transit_ops \n"); - exit(EXIT_FAILURE); - } + test_info test_info{ + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + const auto cli_args = process_args(argc, argv, test_info); scord::network::rpc_client rpc_client{"tcp"}; rpc_client.register_rpcs(); - auto endp = rpc_client.lookup(argv[1]); + auto endp = rpc_client.lookup(cli_args.server_address); fmt::print( stdout, "Calling ADM_in_transit_ops remote procedure on {} -> access method: {} ...\n", - argv[1], argv[2]); + cli_args.controller_address, argv[2]); ADM_in_transit_ops_in_t in; in.in_transit = argv[2]; ADM_in_transit_ops_out_t out; diff --git a/examples/cxx/ADM_link_transfer_to_data_operation.cpp b/examples/cxx/ADM_link_transfer_to_data_operation.cpp index 9c993c08af15db4d4a986cac1df2001af5905381..2227afd1e9ef3095e524c8d65252c0cbd9c863dd 100644 --- a/examples/cxx/ADM_link_transfer_to_data_operation.cpp +++ b/examples/cxx/ADM_link_transfer_to_data_operation.cpp @@ -24,19 +24,20 @@ #include #include +#include "common.hpp" int main(int argc, char* argv[]) { - if(argc != 2) { - fmt::print(stderr, "ERROR: no location provided\n"); - fmt::print( - stderr, - "Usage: ADM_link_transfer_to_data_operation \n"); - exit(EXIT_FAILURE); - } + test_info test_info{ + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + const auto cli_args = process_args(argc, argv, test_info); - scord::server server{"tcp", argv[1]}; + scord::server server{"tcp", cli_args.server_address}; ADM_job_t job{}; ADM_data_operation_t op{}; diff --git a/examples/cxx/ADM_ping.cpp b/examples/cxx/ADM_ping.cpp index 8570c17baadd6e4607098227f8d83841c0270e93..ef796074bc7d6f9ba4aad2dbf59d2394157421de 100644 --- a/examples/cxx/ADM_ping.cpp +++ b/examples/cxx/ADM_ping.cpp @@ -24,17 +24,20 @@ #include #include +#include "common.hpp" int main(int argc, char* argv[]) { - if(argc != 2) { - fmt::print(stderr, "ERROR: no server address provided\n"); - fmt::print(stderr, "Usage: ADM_ping \n"); - exit(EXIT_FAILURE); - } + test_info test_info{ + .name = TESTNAME, + .requires_server = true, + .requires_controller = false, + }; + + const auto cli_args = process_args(argc, argv, test_info); - scord::server server{"tcp", argv[1]}; + scord::server server{"tcp", cli_args.server_address}; try { scord::ping(server); diff --git a/examples/cxx/ADM_register_adhoc_storage.cpp b/examples/cxx/ADM_register_adhoc_storage.cpp index 98b00c56d4808ced12d4894cbd2ec909a7e86227..0dfd0f9ba7ccfea5e2de05ec45105d0c67ebbb5b 100644 --- a/examples/cxx/ADM_register_adhoc_storage.cpp +++ b/examples/cxx/ADM_register_adhoc_storage.cpp @@ -34,14 +34,15 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fmt::print(stderr, "ERROR: no location provided\n"); - fmt::print(stderr, - "Usage: ADM_register_adhoc_storage \n"); - exit(EXIT_FAILURE); - } + test_info test_info{ + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + const auto cli_args = process_args(argc, argv, test_info); - scord::server server{"tcp", argv[1]}; + scord::server server{"tcp", cli_args.server_address}; const auto adhoc_nodes = prepare_nodes(NADHOC_NODES); const auto inputs = prepare_datasets("input-dataset-{}", NINPUTS); @@ -49,6 +50,7 @@ main(int argc, char* argv[]) { std::string name = "adhoc_storage_42"; const auto adhoc_storage_ctx = scord::adhoc_storage::ctx{ + cli_args.controller_address, scord::adhoc_storage::execution_mode::separate_new, scord::adhoc_storage::access_type::read_write, 100, false}; const auto adhoc_resources = scord::adhoc_storage::resources{adhoc_nodes}; diff --git a/examples/cxx/ADM_register_job.cpp b/examples/cxx/ADM_register_job.cpp index 267f56ad418b7ec97cfb0e919704fa489a2ec65f..55ac84d6570dc2739a12d9ce07846cdbfcc78e26 100644 --- a/examples/cxx/ADM_register_job.cpp +++ b/examples/cxx/ADM_register_job.cpp @@ -34,13 +34,15 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fmt::print(stderr, "ERROR: no server address provided\n"); - fmt::print(stderr, "Usage: ADM_register_job \n"); - exit(EXIT_FAILURE); - } + test_info test_info{ + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + const auto cli_args = process_args(argc, argv, test_info); - scord::server server{"tcp", argv[1]}; + scord::server server{"tcp", cli_args.server_address}; const auto job_nodes = prepare_nodes(NJOB_NODES); const auto adhoc_nodes = prepare_nodes(NADHOC_NODES); @@ -49,6 +51,7 @@ main(int argc, char* argv[]) { std::string name = "adhoc_storage_42"; const auto adhoc_storage_ctx = scord::adhoc_storage::ctx{ + cli_args.controller_address, scord::adhoc_storage::execution_mode::separate_new, scord::adhoc_storage::access_type::read_write, 100, false}; const auto adhoc_resources = scord::adhoc_storage::resources{adhoc_nodes}; diff --git a/examples/cxx/ADM_register_pfs_storage.cpp b/examples/cxx/ADM_register_pfs_storage.cpp index 712409dc1d287ccbd438180da46365f27b0aaa39..1078262c91a9233a35a53175064961d7fe7f28dd 100644 --- a/examples/cxx/ADM_register_pfs_storage.cpp +++ b/examples/cxx/ADM_register_pfs_storage.cpp @@ -24,19 +24,21 @@ #include #include +#include "common.hpp" int main(int argc, char* argv[]) { - if(argc != 2) { - fmt::print(stderr, "ERROR: no server address provided\n"); - fmt::print(stderr, - "Usage: ADM_register_pfs_storage \n"); - exit(EXIT_FAILURE); - } + test_info test_info{ + .name = TESTNAME, + .requires_server = true, + .requires_controller = false, + }; + + const auto cli_args = process_args(argc, argv, test_info); - scord::server server{"tcp", argv[1]}; + scord::server server{"tcp", cli_args.server_address}; std::string pfs_name = "gpfs_scratch"; std::string pfs_mount = "/gpfs/scratch"; diff --git a/examples/cxx/ADM_remove_adhoc_storage.cpp b/examples/cxx/ADM_remove_adhoc_storage.cpp index 9459663b809ac91d783ed5d51d569710e1e8e27b..aa496ee6fd002006a39fa7ce4626b5a698b85980 100644 --- a/examples/cxx/ADM_remove_adhoc_storage.cpp +++ b/examples/cxx/ADM_remove_adhoc_storage.cpp @@ -34,14 +34,15 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fmt::print(stderr, "ERROR: no location provided\n"); - fmt::print(stderr, - "Usage: ADM_remove_adhoc_storage \n"); - exit(EXIT_FAILURE); - } + test_info test_info{ + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + const auto cli_args = process_args(argc, argv, test_info); - scord::server server{"tcp", argv[1]}; + scord::server server{"tcp", cli_args.server_address}; const auto adhoc_nodes = prepare_nodes(NADHOC_NODES); const auto inputs = prepare_datasets("input-dataset-{}", NINPUTS); @@ -49,6 +50,7 @@ main(int argc, char* argv[]) { std::string name = "adhoc_storage_42"; const auto adhoc_storage_ctx = scord::adhoc_storage::ctx{ + cli_args.controller_address, scord::adhoc_storage::execution_mode::separate_new, scord::adhoc_storage::access_type::read_write, 100, false}; const auto adhoc_resources = scord::adhoc_storage::resources{adhoc_nodes}; diff --git a/examples/cxx/ADM_remove_job.cpp b/examples/cxx/ADM_remove_job.cpp index 37498e12334b4de078305a6a25e2b53f1c4d2628..4a3ae71cdf7b09ad908520267e879a989ae1a6b6 100644 --- a/examples/cxx/ADM_remove_job.cpp +++ b/examples/cxx/ADM_remove_job.cpp @@ -34,13 +34,15 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fmt::print(stderr, "ERROR: no server address provided\n"); - fmt::print(stderr, "Usage: ADM_remove_job \n"); - exit(EXIT_FAILURE); - } + test_info test_info{ + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + const auto cli_args = process_args(argc, argv, test_info); - scord::server server{"tcp", argv[1]}; + scord::server server{"tcp", cli_args.server_address}; const auto job_nodes = prepare_nodes(NJOB_NODES); const auto adhoc_nodes = prepare_nodes(NADHOC_NODES); @@ -49,6 +51,7 @@ main(int argc, char* argv[]) { std::string name = "adhoc_storage_42"; const auto adhoc_storage_ctx = scord::adhoc_storage::ctx{ + cli_args.controller_address, scord::adhoc_storage::execution_mode::separate_new, scord::adhoc_storage::access_type::read_write, 100, false}; diff --git a/examples/cxx/ADM_remove_pfs_storage.cpp b/examples/cxx/ADM_remove_pfs_storage.cpp index c2cdaeec2247e8f13e387e05c18f3c6d7d5e73dc..8e5bd527ea2a0de334092552c4b4b3616a11f082 100644 --- a/examples/cxx/ADM_remove_pfs_storage.cpp +++ b/examples/cxx/ADM_remove_pfs_storage.cpp @@ -24,18 +24,21 @@ #include #include +#include "common.hpp" int main(int argc, char* argv[]) { - if(argc != 2) { - fmt::print(stderr, "ERROR: no server address provided\n"); - fmt::print(stderr, "Usage: ADM_remove_pfs_storage \n"); - exit(EXIT_FAILURE); - } + test_info test_info{ + .name = TESTNAME, + .requires_server = true, + .requires_controller = false, + }; + + const auto cli_args = process_args(argc, argv, test_info); - scord::server server{"tcp", argv[1]}; + scord::server server{"tcp", cli_args.server_address}; std::string pfs_name = "gpfs_scratch"; std::string pfs_mount = "/gpfs/scratch"; diff --git a/examples/cxx/ADM_set_dataset_information.cpp b/examples/cxx/ADM_set_dataset_information.cpp index 9f7b7d33f519a248ccffc4b0f2cfd415c18f62a1..863e677424d113350f2eaeb9f5b4c7a95ab5a1e6 100644 --- a/examples/cxx/ADM_set_dataset_information.cpp +++ b/examples/cxx/ADM_set_dataset_information.cpp @@ -24,19 +24,21 @@ #include #include +#include "common.hpp" int main(int argc, char* argv[]) { - if(argc != 2) { - fmt::print(stderr, "ERROR: no location provided\n"); - fmt::print(stderr, - "Usage: ADM_set_dataset_information \n"); - exit(EXIT_FAILURE); - } + test_info test_info{ + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + const auto cli_args = process_args(argc, argv, test_info); - scord::server server{"tcp", argv[1]}; + scord::server server{"tcp", cli_args.server_address}; ADM_job_t job{}; ADM_dataset_t target{}; diff --git a/examples/cxx/ADM_set_io_resources.cpp b/examples/cxx/ADM_set_io_resources.cpp index c36f2c65c9739eb34fd05101170a6368a75a8ad1..425b4642379614b73bd0115e6669b2c64fdec12e 100644 --- a/examples/cxx/ADM_set_io_resources.cpp +++ b/examples/cxx/ADM_set_io_resources.cpp @@ -24,18 +24,21 @@ #include #include +#include "common.hpp" int main(int argc, char* argv[]) { - if(argc != 2) { - fmt::print(stderr, "ERROR: no location provided\n"); - fmt::print(stderr, "Usage: ADM_set_io_resources \n"); - exit(EXIT_FAILURE); - } + test_info test_info{ + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + const auto cli_args = process_args(argc, argv, test_info); - scord::server server{"tcp", argv[1]}; + scord::server server{"tcp", cli_args.server_address}; ADM_job_t job{}; ADM_adhoc_storage_t tier{}; diff --git a/examples/cxx/ADM_set_qos_constraints.cpp b/examples/cxx/ADM_set_qos_constraints.cpp index 65b798f12fcb07996a744e8ad232d3762af8b8c5..d487b57603e81a9adc07f0bd3a248aea628c9c2f 100644 --- a/examples/cxx/ADM_set_qos_constraints.cpp +++ b/examples/cxx/ADM_set_qos_constraints.cpp @@ -24,18 +24,20 @@ #include #include - +#include "common.hpp" int main(int argc, char* argv[]) { - if(argc != 2) { - fmt::print(stderr, "ERROR: no location provided\n"); - fmt::print(stderr, "Usage: ADM_set_qos_constraints \n"); - exit(EXIT_FAILURE); - } + test_info test_info{ + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + const auto cli_args = process_args(argc, argv, test_info); - scord::server server{"tcp", argv[1]}; + scord::server server{"tcp", cli_args.server_address}; ADM_job_t job{}; ADM_qos_entity_t entity{}; diff --git a/examples/cxx/ADM_set_transfer_priority.cpp b/examples/cxx/ADM_set_transfer_priority.cpp index 040cde0e5dc70d80290aaa604e3150406ef97705..39819b478966842685c233044fc90d3c84d48b09 100644 --- a/examples/cxx/ADM_set_transfer_priority.cpp +++ b/examples/cxx/ADM_set_transfer_priority.cpp @@ -24,19 +24,21 @@ #include #include +#include "common.hpp" int main(int argc, char* argv[]) { - if(argc != 2) { - fmt::print(stderr, "ERROR: no location provided\n"); - fmt::print(stderr, - "Usage: ADM_set_transfer_priority \n"); - exit(EXIT_FAILURE); - } + test_info test_info{ + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + const auto cli_args = process_args(argc, argv, test_info); - scord::server server{"tcp", argv[1]}; + scord::server server{"tcp", cli_args.server_address}; ADM_job_t job{}; ADM_transfer_t tx{}; diff --git a/examples/cxx/ADM_tear_down_adhoc_storage.cpp b/examples/cxx/ADM_tear_down_adhoc_storage.cpp index 229242744f1c6e001891e10401d09d3a01eef293..561676edb1d388cbdf319e7895f3d851e3384936 100644 --- a/examples/cxx/ADM_tear_down_adhoc_storage.cpp +++ b/examples/cxx/ADM_tear_down_adhoc_storage.cpp @@ -34,14 +34,15 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fmt::print(stderr, "ERROR: no location provided\n"); - fmt::print(stderr, - "Usage: ADM_tear_down_adhoc_storage \n"); - exit(EXIT_FAILURE); - } + test_info test_info{ + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + const auto cli_args = process_args(argc, argv, test_info); - scord::server server{"tcp", argv[1]}; + scord::server server{"tcp", cli_args.server_address}; const auto adhoc_nodes = prepare_nodes(NADHOC_NODES); const auto inputs = prepare_datasets("input-dataset-{}", NINPUTS); @@ -49,6 +50,7 @@ main(int argc, char* argv[]) { std::string name = "adhoc_storage_42"; const auto adhoc_storage_ctx = scord::adhoc_storage::ctx{ + cli_args.controller_address, scord::adhoc_storage::execution_mode::separate_new, scord::adhoc_storage::access_type::read_write, 100, false}; const auto adhoc_resources = scord::adhoc_storage::resources{adhoc_nodes}; diff --git a/examples/cxx/ADM_transfer_datasets.cpp b/examples/cxx/ADM_transfer_datasets.cpp index d13cc8ad7a1681b93c3d9719fac6d72bee02c2a1..2b4e6f02c6373f7f404c305a449b97bdb328ba57 100644 --- a/examples/cxx/ADM_transfer_datasets.cpp +++ b/examples/cxx/ADM_transfer_datasets.cpp @@ -37,13 +37,15 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fmt::print(stderr, "ERROR: no server address provided\n"); - fmt::print(stderr, "Usage: ADM_transfer_datasets \n"); - exit(EXIT_FAILURE); - } + test_info test_info{ + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + const auto cli_args = process_args(argc, argv, test_info); - scord::server server{"tcp", argv[1]}; + scord::server server{"tcp", cli_args.server_address}; const auto job_nodes = prepare_nodes(NJOB_NODES); const auto adhoc_nodes = prepare_nodes(NADHOC_NODES); @@ -57,6 +59,7 @@ main(int argc, char* argv[]) { std::string name = "adhoc_storage_42"; const auto adhoc_storage_ctx = scord::adhoc_storage::ctx{ + cli_args.controller_address, scord::adhoc_storage::execution_mode::separate_new, scord::adhoc_storage::access_type::read_write, 100, false}; const auto adhoc_resources = scord::adhoc_storage::resources{adhoc_nodes}; diff --git a/examples/cxx/ADM_update_adhoc_storage.cpp b/examples/cxx/ADM_update_adhoc_storage.cpp index 36cdaf555feccddc51829a5c334781d57b163471..dbb2ac93c1c3fa9be59fed26ae1c89e38db0c3ce 100644 --- a/examples/cxx/ADM_update_adhoc_storage.cpp +++ b/examples/cxx/ADM_update_adhoc_storage.cpp @@ -33,14 +33,15 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fmt::print(stderr, "ERROR: no location provided\n"); - fmt::print(stderr, - "Usage: ADM_update_adhoc_storage \n"); - exit(EXIT_FAILURE); - } + test_info test_info{ + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + const auto cli_args = process_args(argc, argv, test_info); - scord::server server{"tcp", argv[1]}; + scord::server server{"tcp", cli_args.server_address}; const auto adhoc_nodes = prepare_nodes(NADHOC_NODES); const auto new_adhoc_nodes = prepare_nodes(NADHOC_NODES * 2); @@ -49,6 +50,7 @@ main(int argc, char* argv[]) { std::string name = "adhoc_storage_42"; const auto adhoc_storage_ctx = scord::adhoc_storage::ctx{ + cli_args.controller_address, scord::adhoc_storage::execution_mode::separate_new, scord::adhoc_storage::access_type::read_write, 100, false}; const auto adhoc_resources = scord::adhoc_storage::resources{adhoc_nodes}; diff --git a/examples/cxx/ADM_update_job.cpp b/examples/cxx/ADM_update_job.cpp index 72c82031c62875295d49912bb72b4628921ea560..1ee22d589cfbcf9573c5d315aa44344478f00e8e 100644 --- a/examples/cxx/ADM_update_job.cpp +++ b/examples/cxx/ADM_update_job.cpp @@ -34,13 +34,15 @@ int main(int argc, char* argv[]) { - if(argc != 2) { - fmt::print(stderr, "ERROR: no server address provided\n"); - fmt::print(stderr, "Usage: ADM_update_job \n"); - exit(EXIT_FAILURE); - } + test_info test_info{ + .name = TESTNAME, + .requires_server = true, + .requires_controller = true, + }; + + const auto cli_args = process_args(argc, argv, test_info); - scord::server server{"tcp", argv[1]}; + scord::server server{"tcp", cli_args.server_address}; const auto job_nodes = prepare_nodes(NJOB_NODES); const auto new_job_nodes = prepare_nodes(NJOB_NODES * 2); @@ -51,6 +53,7 @@ main(int argc, char* argv[]) { const auto gkfs_storage = scord::register_adhoc_storage( server, "foobar", scord::adhoc_storage::type::gekkofs, scord::adhoc_storage::ctx{ + cli_args.controller_address, scord::adhoc_storage::execution_mode::separate_new, scord::adhoc_storage::access_type::read_write, 100, false}, scord::adhoc_storage::resources{adhoc_nodes}); diff --git a/examples/cxx/ADM_update_pfs_storage.cpp b/examples/cxx/ADM_update_pfs_storage.cpp index 74fea88b54c0df55286dd25c28d7e0aaa3e1e5ff..019fe1104fa0ffb466822cacb1db9dcca6a8168b 100644 --- a/examples/cxx/ADM_update_pfs_storage.cpp +++ b/examples/cxx/ADM_update_pfs_storage.cpp @@ -24,18 +24,21 @@ #include #include +#include "common.hpp" int main(int argc, char* argv[]) { - if(argc != 2) { - fmt::print(stderr, "ERROR: no server address provided\n"); - fmt::print(stderr, "Usage: ADM_update_pfs_storage \n"); - exit(EXIT_FAILURE); - } + test_info test_info{ + .name = TESTNAME, + .requires_server = true, + .requires_controller = false, + }; + + const auto cli_args = process_args(argc, argv, test_info); - scord::server server{"tcp", argv[1]}; + scord::server server{"tcp", cli_args.server_address}; std::string pfs_name = "gpfs_scratch"; std::string pfs_mount = "/gpfs/scratch"; diff --git a/examples/cxx/CMakeLists.txt b/examples/cxx/CMakeLists.txt index 0b4ca7469cc0a3a3a06ac4c5d61be2320d7707fe..9b828a7aea5f31eed193aba2f5cff47582307419 100644 --- a/examples/cxx/CMakeLists.txt +++ b/examples/cxx/CMakeLists.txt @@ -22,16 +22,12 @@ # SPDX-License-Identifier: GPL-3.0-or-later # ################################################################################ -list(APPEND examples_cxx - # ping - ADM_ping +list(APPEND cxx_examples_with_controller # job ADM_register_job ADM_update_job ADM_remove_job # adhoc storage ADM_register_adhoc_storage ADM_update_adhoc_storage ADM_remove_adhoc_storage ADM_deploy_adhoc_storage ADM_tear_down_adhoc_storage - # pfs storage - ADM_register_pfs_storage ADM_update_pfs_storage ADM_remove_pfs_storage # transfers ADM_transfer_datasets ADM_get_transfer_priority ADM_set_transfer_priority ADM_cancel_transfer ADM_get_pending_transfers @@ -45,11 +41,18 @@ list(APPEND examples_cxx ADM_get_statistics ADM_set_dataset_information ADM_set_io_resources ) +list(APPEND cxx_examples_without_controller + # ping + ADM_ping + # pfs storage + ADM_register_pfs_storage ADM_update_pfs_storage ADM_remove_pfs_storage + ) + add_library(cxx_examples_common STATIC) target_sources(cxx_examples_common PUBLIC common.hpp PRIVATE common.cpp) target_link_libraries(cxx_examples_common libscord_cxx_types) -foreach(example IN LISTS examples_cxx) +foreach(example IN LISTS cxx_examples_with_controller cxx_examples_without_controller) add_executable(${example}_cxx) target_sources(${example}_cxx PRIVATE ${example}.cpp) target_link_libraries(${example}_cxx @@ -57,10 +60,8 @@ foreach(example IN LISTS examples_cxx) set_target_properties(${example}_cxx PROPERTIES OUTPUT_NAME ${example}) endforeach() -set(CXX_TEST_ID 0) - if(SCORD_BUILD_TESTS) - foreach(example IN LISTS examples_cxx) + foreach(example IN LISTS cxx_examples_with_controller) # prepare environment for the RPC test itself and its validation test set(TEST_NAME "${example}_cxx_test") @@ -72,17 +73,48 @@ if(SCORD_BUILD_TESTS) list(APPEND TEST_ENV LIBSCORD_LOG_OUTPUT=${TEST_DIRECTORY}/libscord.log) add_test(run_${TEST_NAME} ${example} - ${SCORD_TRANSPORT_PROTOCOL}://${SCORD_BIND_ADDRESS}:${SCORD_BIND_PORT}) + ${SCORD_ADDRESS_STRING} + ${SCORD_CTL_ADDRESS_STRING}) set_tests_properties(run_${TEST_NAME} - PROPERTIES FIXTURES_REQUIRED scord_daemon - ENVIRONMENT "${TEST_ENV}" - ) + PROPERTIES FIXTURES_REQUIRED "scord_daemon;scord_ctl" + ENVIRONMENT "${TEST_ENV}") add_test(validate_${TEST_NAME} ${CMAKE_SOURCE_DIR}/ci/check_rpcs.py + ${example} ${TEST_DIRECTORY}/libscord.log ${SCORD_TESTS_DIRECTORY}/scord_daemon/scord_daemon.log + ${SCORD_ADDRESS_STRING} + ${SCORD_TESTS_DIRECTORY}/scord_daemon/scord_ctl.log + ${SCORD_CTL_ADDRESS_STRING} + ) + set_tests_properties(validate_${TEST_NAME} + PROPERTIES DEPENDS stop_scord_daemon + ) + endforeach() + + foreach(example IN LISTS cxx_examples_without_controller) + + # prepare environment for the RPC test itself and its validation test + set(TEST_NAME "${example}_cxx_test") + set(TEST_DIRECTORY "${SCORD_TESTS_DIRECTORY}/${TEST_NAME}") + file(MAKE_DIRECTORY ${TEST_DIRECTORY}) + + set(TEST_ENV) + list(APPEND TEST_ENV LIBSCORD_LOG=1) + list(APPEND TEST_ENV LIBSCORD_LOG_OUTPUT=${TEST_DIRECTORY}/libscord.log) + + add_test(run_${TEST_NAME} ${example} ${SCORD_ADDRESS_STRING}) + set_tests_properties(run_${TEST_NAME} + PROPERTIES FIXTURES_REQUIRED scord_daemon + ENVIRONMENT "${TEST_ENV}") + + add_test(validate_${TEST_NAME} + ${CMAKE_SOURCE_DIR}/ci/check_rpcs.py ${example} + ${TEST_DIRECTORY}/libscord.log + ${SCORD_TESTS_DIRECTORY}/scord_daemon/scord_daemon.log + ${SCORD_ADDRESS_STRING} ) set_tests_properties(validate_${TEST_NAME} PROPERTIES DEPENDS stop_scord_daemon diff --git a/examples/cxx/common.cpp b/examples/cxx/common.cpp index d0acaafcf4ed24949996f57ecf5f51dd30c28fa4..cf83a8a90369d9b5145576297ac78f0870c8bf36 100644 --- a/examples/cxx/common.cpp +++ b/examples/cxx/common.cpp @@ -1,5 +1,33 @@ #include "common.hpp" +using std::string_literals::operator""s; + +cli_args +process_args(int argc, char* argv[], const test_info& test_info) { + + int required_args = 1; + + if(test_info.requires_server) { + ++required_args; + } + + if(test_info.requires_controller) { + ++required_args; + } + + if(argc != required_args) { + fmt::print(stderr, "ERROR: missing arguments\n"); + fmt::print(stderr, "Usage: {}{}{}\n", test_info.name, + test_info.requires_server ? " " : "", + test_info.requires_controller ? " " + : ""); + exit(EXIT_FAILURE); + } + + return cli_args{test_info.requires_server ? std::string{argv[1]} : ""s, + test_info.requires_controller ? std::string{argv[2]} : ""s}; +} + std::vector prepare_nodes(size_t n) { std::vector nodes; diff --git a/examples/cxx/common.hpp b/examples/cxx/common.hpp index ee76624c23f51dc0478600766950c045a31bc212..374ad2644fff45251062ba13f54644f12fff9754 100644 --- a/examples/cxx/common.hpp +++ b/examples/cxx/common.hpp @@ -4,6 +4,24 @@ #include #include +#define TESTNAME \ + (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 \ + : __FILE__) + +struct test_info { + std::string name; + bool requires_server; + bool requires_controller; +}; + +struct cli_args { + std::string server_address; + std::string controller_address; +}; + +cli_args +process_args(int argc, char* argv[], const test_info& test_info); + std::vector prepare_nodes(size_t n); diff --git a/src/common/abt_cxx/shared_mutex.hpp b/src/common/abt_cxx/shared_mutex.hpp index 402cfed19d4a0ffd008e560310b9c6615aff7748..a3d924e956b585a4726f3123dec8d555d9d6b4d6 100644 --- a/src/common/abt_cxx/shared_mutex.hpp +++ b/src/common/abt_cxx/shared_mutex.hpp @@ -23,6 +23,7 @@ *****************************************************************************/ #include +#include #include #include diff --git a/src/common/logger/logger.cpp b/src/common/logger/logger.cpp index e46b295f25595df6c9735bc7615778132873a46e..391dd300eafbed38eada8c626fa8dd009d218731 100644 --- a/src/common/logger/logger.cpp +++ b/src/common/logger/logger.cpp @@ -32,24 +32,26 @@ logger_setup(const char* ident, logger_type type, const char* log_file) { constexpr auto get_cxx_type = [](logger_type t) { switch(t) { case CONSOLE_LOGGER: - return scord::logger_type::console; + return logger::logger_type::console; case CONSOLE_COLOR_LOGGER: - return scord::logger_type::console_color; + return logger::logger_type::console_color; case FILE_LOGGER: - return scord::logger_type::file; + return logger::logger_type::file; case SYSLOG_LOGGER: - return scord::logger_type::syslog; + return logger::logger_type::syslog; default: - return scord::logger_type::console; + return logger::logger_type::console; } }; - scord::logger::create_global_logger(ident, get_cxx_type(type), log_file); + logger::create_global_logger(ident, get_cxx_type(type), log_file); } void logger_log(enum logger_level level, const char* fmt, ...) { - if(const auto logger = scord::logger::get_global_logger(); logger) { + using logger::logger; + + if(const auto logger = logger::get_global_logger(); logger) { std::array msg; // NOLINT va_list args; @@ -79,7 +81,9 @@ logger_log(enum logger_level level, const char* fmt, ...) { void logger_destroy() { - if(scord::logger::get_global_logger()) { - scord::logger::destroy_global_logger(); + using logger::logger; + + if(logger::get_global_logger()) { + ::logger::destroy_global_logger(); } } diff --git a/src/common/logger/logger.hpp b/src/common/logger/logger.hpp index df565cfaa51a50c3386228529c091b892243d346..09611fb24f7b4d527a5f603df60b2678461872c1 100644 --- a/src/common/logger/logger.hpp +++ b/src/common/logger/logger.hpp @@ -50,7 +50,7 @@ ptr(const T* p) { namespace fs = std::filesystem; -namespace scord { +namespace logger { enum logger_type { console, @@ -64,7 +64,7 @@ class logger_config { public: logger_config() = default; - explicit logger_config(std::string ident, scord::logger_type type, + explicit logger_config(std::string ident, logger_type type, std::optional log_file = {}) : m_ident(std::move(ident)), m_type(type), m_log_file(std::move(log_file)) {} @@ -74,7 +74,7 @@ public: return m_ident; } - scord::logger_type + logger_type type() const { return m_type; } @@ -86,7 +86,7 @@ public: private: std::string m_ident; - scord::logger_type m_type = console_color; + logger_type m_type = console_color; std::optional m_log_file; }; @@ -165,28 +165,10 @@ public: spdlog::shutdown(); } - // the following static functions can be used to interact - // with a globally registered logger instance - - template - static inline void - create_global_logger(Args&&... args) { - global_logger() = std::make_shared(args...); - } - - static inline void - register_global_logger(logger&& lg) { - global_logger() = std::make_shared(std::move(lg)); - } - - static inline std::shared_ptr& + static std::shared_ptr& get_global_logger() { - return global_logger(); - } - - static inline void - destroy_global_logger() { - global_logger().reset(); + static std::shared_ptr s_global_logger; + return s_global_logger; } // the following member functions can be used to interact @@ -307,18 +289,38 @@ public: return ss.str(); } -private: - static std::shared_ptr& - global_logger() { - static std::shared_ptr s_global_logger; - return s_global_logger; - } - private: std::shared_ptr m_internal_logger; std::string m_type; }; -} // namespace scord +// the following static functions can be used to interact +// with a globally registered logger instance + +template +static inline void +create_global_logger(Args&&... args) { + logger::get_global_logger() = std::make_shared(args...); +} + +static inline void +register_global_logger(logger&& lg) { + logger::get_global_logger() = std::make_shared(std::move(lg)); +} + +static inline void +destroy_global_logger() { + logger::get_global_logger().reset(); +} + +static inline void +flush_global_logger() { + if(logger::get_global_logger()) { + logger::get_global_logger()->flush(); + } +} + + +} // namespace logger #endif /* SCORD_LOGGER_HPP */ diff --git a/src/common/logger/macros.h b/src/common/logger/macros.h index f4ee6ac614134544cb432fc9d6393dc94b2a62bf..1da2c6d3c7fa5737346ee10c5e1c6885c1d4b754 100644 --- a/src/common/logger/macros.h +++ b/src/common/logger/macros.h @@ -31,7 +31,7 @@ #define LOGGER_INFO(...) \ do { \ - using scord::logger; \ + using logger::logger; \ if(logger::get_global_logger()) { \ logger::get_global_logger()->info(__VA_ARGS__); \ } \ @@ -42,7 +42,7 @@ #define LOGGER_DEBUG(...) \ do { \ - using scord::logger; \ + using logger::logger; \ if(logger::get_global_logger()) { \ logger::get_global_logger()->debug(__VA_ARGS__); \ } \ @@ -50,7 +50,7 @@ #define LOGGER_FLUSH() \ do { \ - using scord::logger; \ + using logger::logger; \ if(logger::get_global_logger()) { \ logger::get_global_logger()->flush(); \ } \ @@ -69,7 +69,7 @@ #define LOGGER_WARN(...) \ do { \ - using scord::logger; \ + using logger::logger; \ if(logger::get_global_logger()) { \ logger::get_global_logger()->warn(__VA_ARGS__); \ } \ @@ -77,7 +77,7 @@ #define LOGGER_ERROR(...) \ do { \ - using scord::logger; \ + using logger::logger; \ if(logger::get_global_logger()) { \ logger::get_global_logger()->error(__VA_ARGS__); \ } \ @@ -85,7 +85,7 @@ #define LOGGER_ERRNO(...) \ do { \ - using scord::logger; \ + using logger::logger; \ if(logger::get_global_logger()) { \ logger::get_global_logger()->error_errno(__VA_ARGS__); \ } \ @@ -93,7 +93,8 @@ #define LOGGER_CRITICAL(...) \ do { \ - using scord::logger; \ + using logger::logger; \ + using logger::logger; \ if(logger::get_global_logger()) { \ logger::get_global_logger()->critical(__VA_ARGS__); \ } \ diff --git a/src/common/net/CMakeLists.txt b/src/common/net/CMakeLists.txt index 68c5658ea7d451f9b95af396c41b433fec1831d5..983e7df36a808c48499da5f952ba6dd05da491a7 100644 --- a/src/common/net/CMakeLists.txt +++ b/src/common/net/CMakeLists.txt @@ -25,7 +25,7 @@ add_library(_rpc_client STATIC) target_sources( _rpc_client - INTERFACE endpoint.hpp client.hpp request.hpp serialization.hpp + INTERFACE endpoint.hpp client.hpp request.hpp serialization.hpp utilities.hpp PRIVATE endpoint.cpp client.cpp ) @@ -35,8 +35,8 @@ set_property(TARGET _rpc_client PROPERTY POSITION_INDEPENDENT_CODE ON) add_library(_rpc_server STATIC) target_sources( _rpc_server - INTERFACE server.hpp request.hpp serialization.hpp - PRIVATE server.cpp + INTERFACE endpoint.hpp server.hpp request.hpp serialization.hpp utilities.hpp + PRIVATE server.cpp endpoint.cpp ) target_link_libraries(_rpc_server PUBLIC common::logger thallium) diff --git a/src/common/net/client.cpp b/src/common/net/client.cpp index 6617beac2c798cecc425bd4f9e259f4b2c954154..1c56a4aa62b2be76ce4631536d24a6ac9997cac0 100644 --- a/src/common/net/client.cpp +++ b/src/common/net/client.cpp @@ -29,17 +29,16 @@ using namespace std::literals; -namespace scord::network { +namespace network { client::client(const std::string& protocol) - : m_engine(std::make_shared(protocol, - THALLIUM_CLIENT_MODE)) {} + : m_engine(protocol, THALLIUM_CLIENT_MODE) {} std::optional client::lookup(const std::string& address) noexcept { try { - return endpoint{m_engine, m_engine->lookup(address)}; + return endpoint{m_engine, m_engine.lookup(address)}; } catch(const std::exception& ex) { LOGGER_ERROR("client::lookup() failed: {}", ex.what()); return std::nullopt; @@ -49,11 +48,11 @@ client::lookup(const std::string& address) noexcept { std::string client::self_address() const noexcept { try { - return m_engine->self(); + return m_engine.self(); } catch(const std::exception& ex) { LOGGER_ERROR("client::self_address() failed: {}", ex.what()); return "unknown"s; } } -} // namespace scord::network +} // namespace network diff --git a/src/common/net/client.hpp b/src/common/net/client.hpp index c58773506b4236b7db7b1ef27cf2284aa3bccaa2..c371ffb6cfb081ad83f6167781749051037be60e 100644 --- a/src/common/net/client.hpp +++ b/src/common/net/client.hpp @@ -22,13 +22,13 @@ * SPDX-License-Identifier: GPL-3.0-or-later *****************************************************************************/ -#ifndef SCORD_CLIENT_HPP -#define SCORD_CLIENT_HPP +#ifndef NETWORK_CLIENT_HPP +#define NETWORK_CLIENT_HPP #include #include -namespace scord::network { +namespace network { class endpoint; @@ -42,9 +42,9 @@ public: self_address() const noexcept; private: - std::shared_ptr m_engine; + thallium::engine m_engine; }; -} // namespace scord::network +} // namespace network -#endif // SCORD_CLIENT_HPP +#endif // NETWORK_CLIENT_HPP diff --git a/src/common/net/endpoint.cpp b/src/common/net/endpoint.cpp index 81ec5204387c81e055134fd0d0533bc4255e784b..25ed4edd65664926ad3728a127be3cbc4ce59d3a 100644 --- a/src/common/net/endpoint.cpp +++ b/src/common/net/endpoint.cpp @@ -26,15 +26,14 @@ #include -namespace scord::network { +namespace network { -endpoint::endpoint(std::shared_ptr engine, - thallium::endpoint endpoint) - : m_engine(std::move(engine)), m_endpoint(std::move(endpoint)) {} +endpoint::endpoint(thallium::engine& engine, thallium::endpoint endpoint) + : m_engine(engine), m_endpoint(std::move(endpoint)) {} std::string endpoint::address() const { return m_endpoint; } -} // namespace scord::network +} // namespace network diff --git a/src/common/net/endpoint.hpp b/src/common/net/endpoint.hpp index 208498ea7677c24dc955c0bb91e5679ce5fdb7a4..1c8db2aae471d76f57335a3fdf959d3f9a1b0bd2 100644 --- a/src/common/net/endpoint.hpp +++ b/src/common/net/endpoint.hpp @@ -22,20 +22,19 @@ * SPDX-License-Identifier: GPL-3.0-or-later *****************************************************************************/ -#ifndef SCORD_ENDPOINT_HPP -#define SCORD_ENDPOINT_HPP +#ifndef NETWORK_ENDPOINT_HPP +#define NETWORK_ENDPOINT_HPP #include #include #include -namespace scord::network { +namespace network { class endpoint { public: - endpoint(std::shared_ptr engine, - thallium::endpoint endpoint); + endpoint(thallium::engine& engine, thallium::endpoint endpoint); std::string address() const; @@ -45,7 +44,7 @@ public: call(const std::string& rpc_name, Args&&... args) const { try { - const auto rpc = m_engine->define(rpc_name); + const auto rpc = m_engine.define(rpc_name); return std::make_optional( rpc.on(m_endpoint)(std::forward(args)...)); } catch(const std::exception& ex) { @@ -65,10 +64,10 @@ public: } private: - std::shared_ptr m_engine; + mutable thallium::engine m_engine; thallium::endpoint m_endpoint; }; -} // namespace scord::network +} // namespace network -#endif // SCORD_ENDPOINT_HPP +#endif // NETWORK_ENDPOINT_HPP diff --git a/src/common/net/request.hpp b/src/common/net/request.hpp index 0f4ad7c52cdd1920b6ccb10ef245268bca961f88..3154db26e26c59c2e596c7b0861572aad37effd3 100644 --- a/src/common/net/request.hpp +++ b/src/common/net/request.hpp @@ -22,13 +22,13 @@ * SPDX-License-Identifier: GPL-3.0-or-later *****************************************************************************/ -#ifndef SCORD_NET_REQUEST_HPP -#define SCORD_NET_REQUEST_HPP +#ifndef NETWORK_REQUEST_HPP +#define NETWORK_REQUEST_HPP #include #include -namespace scord::network { +namespace network { using request = thallium::request; @@ -100,6 +100,6 @@ private: using response_with_id = response_with_value; -} // namespace scord::network +} // namespace network -#endif // SCORD_NET_REQUEST_HPP +#endif // NETWORK_REQUEST_HPP diff --git a/src/common/net/serialization.hpp b/src/common/net/serialization.hpp index fbca80d676fec4fdc528d417f08be54e39819a3d..1e01356075b8cb59d8e285d42c44dc7b2f47f9fb 100644 --- a/src/common/net/serialization.hpp +++ b/src/common/net/serialization.hpp @@ -22,8 +22,8 @@ * SPDX-License-Identifier: GPL-3.0-or-later *****************************************************************************/ -#ifndef SCORD_SERIALIZATION_HPP -#define SCORD_SERIALIZATION_HPP +#ifndef NETWORK_SERIALIZATION_HPP +#define NETWORK_SERIALIZATION_HPP #include #include @@ -57,13 +57,13 @@ CEREAL_SAVE_FUNCTION_NAME(Archive& ar, const std::filesystem::path& in) { } // namespace cereal -namespace scord::network::serialization { +namespace network::serialization { #define SCORD_SERIALIZATION_NVP CEREAL_NVP using input_archive = thallium::proc_input_archive<>; using output_archive = thallium::proc_output_archive<>; -} // namespace scord::network::serialization +} // namespace network::serialization -#endif // SCORD_SERIALIZATION_HPP +#endif // NETWORK_SERIALIZATION_HPP diff --git a/src/common/net/server.cpp b/src/common/net/server.cpp index 616dc90cfc22cda6780334b0be2254ef031409d8..494bc2197cce7fb3ee9c2c394f91879f04ac7ea0 100644 --- a/src/common/net/server.cpp +++ b/src/common/net/server.cpp @@ -40,10 +40,11 @@ #include #include #include "server.hpp" +#include "endpoint.hpp" using namespace std::literals; -namespace scord::network { +namespace network { server::server(std::string name, std::string address, bool daemonize, fs::path rundir) @@ -51,7 +52,7 @@ server::server(std::string name, std::string address, bool daemonize, m_daemonize(daemonize), m_rundir(std::move(rundir)), m_pidfile(daemonize ? std::make_optional(m_rundir / (m_name + ".pid")) : std::nullopt), - m_logger_config(m_name, scord::logger_type::console_color), + m_logger_config(m_name, logger::logger_type::console_color), m_network_engine(m_address, THALLIUM_SERVER_MODE) {} server::~server() = default; @@ -212,7 +213,7 @@ server::signal_handler(int signum) { case SIGHUP: LOGGER_WARN("A signal (SIGHUP) occurred."); - logger::get_global_logger()->flush(); + logger::flush_global_logger(); break; default: @@ -224,25 +225,25 @@ void server::init_logger() { switch(m_logger_config.type()) { - case console_color: + case logger::logger_type::console_color: logger::create_global_logger(m_logger_config.ident(), - logger_type::console_color); + logger::logger_type::console_color); break; - case syslog: + case logger::logger_type::syslog: logger::create_global_logger(m_logger_config.ident(), - logger_type::syslog); + logger::logger_type::syslog); break; - case file: + case logger::logger_type::file: if(m_logger_config.log_file().has_value()) { logger::create_global_logger(m_logger_config.ident(), - logger_type::file, + logger::logger_type::file, *m_logger_config.log_file()); break; } [[fallthrough]]; - case console: + case logger::logger_type::console: logger::create_global_logger(m_logger_config.ident(), - logger_type::console); + logger::logger_type::console); break; } } @@ -302,6 +303,26 @@ server::print_farewell() { LOGGER_INFO("{:=>{}}", "", farewell.size()); } +std::optional +server::lookup(const std::string& address) noexcept { + try { + return endpoint{m_network_engine, m_network_engine.lookup(address)}; + } catch(const std::exception& ex) { + LOGGER_ERROR("server::lookup() failed: {}", ex.what()); + return std::nullopt; + } +} + +std::string +server::self_address() const noexcept { + try { + return m_network_engine.self(); + } catch(const std::exception& ex) { + LOGGER_ERROR("server::self_address() failed: {}", ex.what()); + return "unknown"s; + } +} + int server::run() { @@ -380,4 +401,4 @@ server::shutdown() { m_network_engine.finalize(); } -} // namespace scord::network +} // namespace network diff --git a/src/common/net/server.hpp b/src/common/net/server.hpp index a36a07b4bbd9d5f2a92b31dac99078cc9f5fe6c8..bafa8b82df13c2c2dc9b17bbebf536b5ed93f772 100644 --- a/src/common/net/server.hpp +++ b/src/common/net/server.hpp @@ -22,8 +22,8 @@ * SPDX-License-Identifier: GPL-3.0-or-later *****************************************************************************/ -#ifndef SCORD_SERVER_HPP -#define SCORD_SERVER_HPP +#ifndef SCORD_RPC_SERVER +#define SCORD_RPC_SERVER #include #include @@ -33,10 +33,15 @@ #include #include -namespace scord::network { +namespace network { + +class endpoint; using request = thallium::request; +template +using provider = thallium::provider; + class server { public: @@ -47,11 +52,17 @@ public: template void - configure_logger(scord::logger_type type, Args&&... args) { - m_logger_config = - logger_config(m_name, type, std::forward(args)...); + configure_logger(logger::logger_type type, Args&&... args) { + m_logger_config = logger::logger_config(m_name, type, + std::forward(args)...); } + std::optional + lookup(const std::string& address) noexcept; + + std::string + self_address() const noexcept; + int run(); void @@ -93,11 +104,15 @@ private: bool m_daemonize; fs::path m_rundir; std::optional m_pidfile; - logger_config m_logger_config; + logger::logger_config m_logger_config; + +protected: thallium::engine m_network_engine; + +private: scord::utils::signal_listener m_signal_listener; }; -} // namespace scord::network +} // namespace network -#endif // SCORD_SERVER_HPP +#endif // SCORD_RPC_SERVER diff --git a/src/common/net/utilities.hpp b/src/common/net/utilities.hpp new file mode 100644 index 0000000000000000000000000000000000000000..cc1dda421a4df64194e88428fdfa9f204f11fa9a --- /dev/null +++ b/src/common/net/utilities.hpp @@ -0,0 +1,135 @@ +/****************************************************************************** + * Copyright 2021-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 scord. + * + * scord 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. + * + * scord 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 scord. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + *****************************************************************************/ + + +#ifndef NETWORK_UTILITIES_HPP +#define NETWORK_UTILITIES_HPP + +#include +#include +#include +#include +#include +#include + +namespace network { + +class rpc_info { +private: + static std::uint64_t + new_id() { + static std::atomic_uint64_t s_current_id; + return s_current_id++; + } + +public: + rpc_info(std::uint64_t id, std::string name, std::string address) + : m_id(id), m_children(0), m_name(std::move(name)), + m_address(std::move(address)) {} + + rpc_info(std::uint64_t id, std::uint64_t pid, std::string name, + std::string address) + : m_id(id), m_pid(pid), m_children(0), m_name(std::move(name)), + m_address(std::move(address)) {} + + template + static rpc_info + create(Args&&... args) { + return {new_id(), std::forward(args)...}; + } + + template + rpc_info + add_child(std::string address) const { + return {m_children, m_id, m_name, std::move(address)}; + } + + constexpr std::uint64_t + id() const { + return m_id; + } + + constexpr std::optional + pid() const { + return m_pid; + } + + const std::string& + name() const { + return m_name; + } + + const std::string& + address() const { + return m_address; + } + +private: + std::uint64_t m_id; + std::optional m_pid; + std::uint64_t m_children; + std::string m_name; + std::string m_address; +}; + +} // namespace network + +template <> +struct fmt::formatter { + + // RPC direction format: + // '<': from self to target (outbound) + // '>': from target to self (inbound) + bool m_outbound = true; + + // Parses format specifications in the form: + constexpr auto + parse(format_parse_context& ctx) { + auto it = ctx.begin(), end = ctx.end(); + + if(it != end && (*it == '<' || *it == '>')) { + m_outbound = *it++ == '<'; + } + + if(it != end && *it != '}') { + ctx.on_error("invalid format"); + } + + return it; + } + + template + constexpr auto + format(const network::rpc_info& rpc, FormatContext& ctx) const { + format_to(ctx.out(), "{}{} id: {} name: {} ", m_outbound ? "<=" : "=>", + rpc.pid() ? fmt::format(" pid: {}", *rpc.pid()) : "", + rpc.id(), std::quoted(rpc.name())); + return m_outbound ? format_to(ctx.out(), "to: {}", + std::quoted(rpc.address())) + : format_to(ctx.out(), "from: {}", + std::quoted(rpc.address())); + } +}; + +#endif // NETWORK_UTILITIES_HPP diff --git a/src/lib/detail/impl.cpp b/src/lib/detail/impl.cpp index ec28bcb799929b100b8e22d959948da019917fb5..4ffb890dacb60402e6ff932fd6d8f9577704c723 100644 --- a/src/lib/detail/impl.cpp +++ b/src/lib/detail/impl.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include "impl.hpp" @@ -46,33 +47,28 @@ struct remote_procedure { namespace scord::detail { +#define RPC_NAME() ("ADM_"s + __FUNCTION__) + scord::error_code ping(const server& srv) { - scord::network::client rpc_client{srv.protocol()}; + network::client rpc_client{srv.protocol()}; - const auto rpc_id = ::api::remote_procedure::new_id(); + const auto rpc = network::rpc_info::create(RPC_NAME(), srv.address()); if(const auto lookup_rv = rpc_client.lookup(srv.address()); lookup_rv.has_value()) { const auto& endp = lookup_rv.value(); - LOGGER_INFO("rpc id: {} name: {} from: {} => " - "body: {{}}", - rpc_id, std::quoted("ADM_"s + __FUNCTION__), - std::quoted(rpc_client.self_address())); + LOGGER_INFO("rpc {:<} body: {{}}", rpc); - if(const auto call_rv = endp.call("ADM_"s + __FUNCTION__); - call_rv.has_value()) { + if(const auto call_rv = endp.call(rpc.name()); call_rv.has_value()) { - const scord::network::generic_response resp{call_rv.value()}; + const network::generic_response resp{call_rv.value()}; LOGGER_EVAL(resp.error_code(), INFO, ERROR, - "rpc id: {} name: {} from: {} <= " - "body: {{retval: {}}} [op_id: {}]", - rpc_id, std::quoted("ADM_"s + __FUNCTION__), - std::quoted(endp.address()), resp.error_code(), - resp.op_id()); + "rpc {:>} body: {{retval: {}}} [op_id: {}]", rpc, + resp.error_code(), resp.op_id()); return resp.error_code(); } @@ -87,34 +83,27 @@ register_job(const server& srv, const job::resources& job_resources, const job::requirements& job_requirements, scord::slurm_job_id slurm_id) { - scord::network::client rpc_client{srv.protocol()}; + network::client rpc_client{srv.protocol()}; - const auto rpc_id = ::api::remote_procedure::new_id(); + const auto rpc = network::rpc_info::create(RPC_NAME(), srv.address()); if(const auto lookup_rv = rpc_client.lookup(srv.address()); lookup_rv.has_value()) { const auto& endp = lookup_rv.value(); - LOGGER_INFO( - "rpc id: {} name: {} from: {} => " - "body: {{job_resources: {}, job_requirements: {}, slurm_id: " - "{}}}", - rpc_id, std::quoted("ADM_"s + __FUNCTION__), - std::quoted(rpc_client.self_address()), job_resources, - job_requirements, slurm_id); + LOGGER_INFO("rpc {:<} body: {{job_resources: {}, job_requirements: {}, " + "slurm_id: {}}}", + rpc, job_resources, job_requirements, slurm_id); - if(const auto call_rv = endp.call("ADM_"s + __FUNCTION__, job_resources, + if(const auto call_rv = endp.call(rpc.name(), job_resources, job_requirements, slurm_id); call_rv.has_value()) { - const scord::network::response_with_id resp{call_rv.value()}; + const network::response_with_id resp{call_rv.value()}; LOGGER_EVAL(resp.error_code(), INFO, ERROR, - "rpc id: {} name: {} from: {} <= " - "body: {{retval: {}, job_id: {}}} [op_id: {}]", - rpc_id, std::quoted("ADM_"s + __FUNCTION__), - std::quoted(endp.address()), resp.error_code(), - resp.value(), resp.op_id()); + "rpc {:>} body: {{retval: {}, job_id: {}}} [op_id: {}]", + rpc, resp.error_code(), resp.value(), resp.op_id()); if(const auto ec = resp.error_code(); !ec) { return tl::make_unexpected(resp.error_code()); @@ -132,32 +121,25 @@ scord::error_code update_job(const server& srv, const job& job, const job::resources& new_resources) { - scord::network::client rpc_client{srv.protocol()}; + network::client rpc_client{srv.protocol()}; - const auto rpc_id = ::api::remote_procedure::new_id(); + const auto rpc = network::rpc_info::create(RPC_NAME(), srv.address()); if(const auto& lookup_rv = rpc_client.lookup(srv.address()); lookup_rv.has_value()) { const auto& endp = lookup_rv.value(); - LOGGER_INFO("rpc id: {} name: {} from: {} => " - "body: {{job_id: {}, new_resources: {}}}", - rpc_id, std::quoted("ADM_"s + __FUNCTION__), - std::quoted(rpc_client.self_address()), job.id(), - new_resources); + LOGGER_INFO("rpc {:<} body: {{job_id: {}, new_resources: {}}}", rpc, + job.id(), new_resources); - if(const auto& call_rv = - endp.call("ADM_"s + __FUNCTION__, job.id(), new_resources); + if(const auto& call_rv = endp.call(rpc.name(), job.id(), new_resources); call_rv.has_value()) { - const scord::network::generic_response resp{call_rv.value()}; + const network::generic_response resp{call_rv.value()}; LOGGER_EVAL(resp.error_code(), INFO, ERROR, - "rpc id: {} name: {} from: {} <= " - "body: {{retval: {}}} [op_id: {}]", - rpc_id, std::quoted("ADM_"s + __FUNCTION__), - std::quoted(endp.address()), resp.error_code(), - resp.op_id()); + "rpc {:>} body: {{retval: {}}} [op_id: {}]", rpc, + resp.error_code(), resp.op_id()); return resp.error_code(); } } @@ -169,30 +151,24 @@ update_job(const server& srv, const job& job, scord::error_code remove_job(const server& srv, const job& job) { - scord::network::client rpc_client{srv.protocol()}; + network::client rpc_client{srv.protocol()}; - const auto rpc_id = ::api::remote_procedure::new_id(); + const auto rpc = network::rpc_info::create(RPC_NAME(), srv.address()); if(const auto& lookup_rv = rpc_client.lookup(srv.address()); lookup_rv.has_value()) { const auto& endp = lookup_rv.value(); - LOGGER_INFO("rpc id: {} name: {} from: {} => " - "body: {{job_id: {}}}", - rpc_id, std::quoted("ADM_"s + __FUNCTION__), - std::quoted(rpc_client.self_address()), job.id()); + LOGGER_INFO("rpc {:<} body: {{job_id: {}}}", rpc, job.id()); - if(const auto& call_rv = endp.call("ADM_"s + __FUNCTION__, job.id()); + if(const auto& call_rv = endp.call(rpc.name(), job.id()); call_rv.has_value()) { - const scord::network::generic_response resp{call_rv.value()}; + const network::generic_response resp{call_rv.value()}; LOGGER_EVAL(resp.error_code(), INFO, ERROR, - "rpc id: {} name: {} from: {} <= " - "body: {{retval: {}}} [op_id: {}]", - rpc_id, std::quoted("ADM_"s + __FUNCTION__), - std::quoted(endp.address()), resp.error_code(), - resp.op_id()); + "rpc {:>} body: {{retval: {}}} [op_id: {}]", rpc, + resp.error_code(), resp.op_id()); return resp.error_code(); } } @@ -207,33 +183,28 @@ register_adhoc_storage(const server& srv, const std::string& name, const adhoc_storage::ctx& ctx, const adhoc_storage::resources& resources) { - scord::network::client rpc_client{srv.protocol()}; + network::client rpc_client{srv.protocol()}; - const auto rpc_id = ::api::remote_procedure::new_id(); + const auto rpc = network::rpc_info::create(RPC_NAME(), srv.address()); if(const auto& lookup_rv = rpc_client.lookup(srv.address()); lookup_rv.has_value()) { const auto& endp = lookup_rv.value(); - LOGGER_INFO("rpc id: {} name: {} from: {} => " - "body: {{name: {}, type: {}, adhoc_ctx: {}, " + LOGGER_INFO("rpc {:<} body: {{name: {}, type: {}, adhoc_ctx: {}, " "adhoc_resources: {}}}", - rpc_id, std::quoted("ADM_"s + __FUNCTION__), - std::quoted(rpc_client.self_address()), name, type, ctx, - resources); + rpc, name, type, ctx, resources); - if(const auto& call_rv = endp.call("ADM_"s + __FUNCTION__, name, type, - ctx, resources); + if(const auto& call_rv = + endp.call(rpc.name(), name, type, ctx, resources); call_rv.has_value()) { - const scord::network::response_with_id resp{call_rv.value()}; + const network::response_with_id resp{call_rv.value()}; - LOGGER_EVAL(resp.error_code(), INFO, ERROR, - "rpc id: {} name: {} from: {} <= " - "body: {{retval: {}, adhoc_id: {}}} [op_id: {}]", - rpc_id, std::quoted("ADM_"s + __FUNCTION__), - std::quoted(endp.address()), resp.error_code(), - resp.value(), resp.op_id()); + LOGGER_EVAL( + resp.error_code(), INFO, ERROR, + "rpc {:>} body: {{retval: {}, adhoc_id: {}}} [op_id: {}]", + rpc, resp.error_code(), resp.value(), resp.op_id()); if(const auto ec = resp.error_code(); !ec) { return tl::make_unexpected(ec); @@ -252,32 +223,26 @@ scord::error_code update_adhoc_storage(const server& srv, const adhoc_storage& adhoc_storage, const adhoc_storage::resources& new_resources) { - scord::network::client rpc_client{srv.protocol()}; + network::client rpc_client{srv.protocol()}; - const auto rpc_id = ::api::remote_procedure::new_id(); + const auto rpc = network::rpc_info::create(RPC_NAME(), srv.address()); if(const auto& lookup_rv = rpc_client.lookup(srv.address()); lookup_rv.has_value()) { const auto& endp = lookup_rv.value(); - LOGGER_INFO("rpc id: {} name: {} from: {} => " - "body: {{adhoc_id: {}, new_resources: {}}}", - rpc_id, std::quoted("ADM_"s + __FUNCTION__), - std::quoted(rpc_client.self_address()), adhoc_storage.id(), - new_resources); + LOGGER_INFO("rpc {:<} body: {{adhoc_id: {}, new_resources: {}}}", rpc, + adhoc_storage.id(), new_resources); - if(const auto& call_rv = endp.call("ADM_"s + __FUNCTION__, - adhoc_storage.id(), new_resources); + if(const auto& call_rv = + endp.call(rpc.name(), adhoc_storage.id(), new_resources); call_rv.has_value()) { - const scord::network::generic_response resp{call_rv.value()}; + const network::generic_response resp{call_rv.value()}; LOGGER_EVAL(resp.error_code(), INFO, ERROR, - "rpc id: {} name: {} from: {} <= " - "body: {{retval: {}}} [op_id: {}]", - rpc_id, std::quoted("ADM_"s + __FUNCTION__), - std::quoted(endp.address()), resp.error_code(), - resp.op_id()); + "rpc {:>} body: {{retval: {}}} [op_id: {}]", rpc, + resp.error_code(), resp.op_id()); return resp.error_code(); } @@ -290,31 +255,24 @@ update_adhoc_storage(const server& srv, const adhoc_storage& adhoc_storage, scord::error_code remove_adhoc_storage(const server& srv, const adhoc_storage& adhoc_storage) { - scord::network::client rpc_client{srv.protocol()}; + network::client rpc_client{srv.protocol()}; - const auto rpc_id = ::api::remote_procedure::new_id(); + const auto rpc = network::rpc_info::create(RPC_NAME(), srv.address()); if(const auto& lookup_rv = rpc_client.lookup(srv.address()); lookup_rv.has_value()) { const auto& endp = lookup_rv.value(); - LOGGER_INFO("rpc id: {} name: {} from: {} => " - "body: {{adhoc_id: {}}}", - rpc_id, std::quoted("ADM_"s + __FUNCTION__), - std::quoted(rpc_client.self_address()), adhoc_storage.id()); + LOGGER_INFO("rpc {:<} body: {{adhoc_id: {}}}", rpc, adhoc_storage.id()); - if(const auto& call_rv = - endp.call("ADM_"s + __FUNCTION__, adhoc_storage.id()); + if(const auto& call_rv = endp.call(rpc.name(), adhoc_storage.id()); call_rv.has_value()) { - const scord::network::generic_response resp{call_rv.value()}; + const network::generic_response resp{call_rv.value()}; LOGGER_EVAL(resp.error_code(), INFO, ERROR, - "rpc id: {} name: {} from: {} <= " - "body: {{retval: {}}} [op_id: {}]", - rpc_id, std::quoted("ADM_"s + __FUNCTION__), - std::quoted(endp.address()), resp.error_code(), - resp.op_id()); + "rpc {:>} body: {{retval: {}}} [op_id: {}]", rpc, + resp.error_code(), resp.op_id()); return resp.error_code(); } @@ -328,31 +286,25 @@ tl::expected register_pfs_storage(const server& srv, const std::string& name, enum pfs_storage::type type, const pfs_storage::ctx& ctx) { - scord::network::client rpc_client{srv.protocol()}; + network::client rpc_client{srv.protocol()}; - const auto rpc_id = ::api::remote_procedure::new_id(); + const auto rpc = network::rpc_info::create(RPC_NAME(), srv.address()); if(const auto& lookup_rv = rpc_client.lookup(srv.address()); lookup_rv.has_value()) { const auto& endp = lookup_rv.value(); - LOGGER_INFO("rpc id: {} name: {} from: {} => " - "body: {{name: {}, type: {}, pfs_ctx: {}}}", - rpc_id, std::quoted("ADM_"s + __FUNCTION__), - std::quoted(rpc_client.self_address()), name, type, ctx); + LOGGER_INFO("rpc {:<} body: {{name: {}, type: {}, pfs_ctx: {}}}", rpc, + name, type, ctx); - if(const auto& call_rv = - endp.call("ADM_"s + __FUNCTION__, name, type, ctx); + if(const auto& call_rv = endp.call(rpc.name(), name, type, ctx); call_rv.has_value()) { - const scord::network::response_with_id resp{call_rv.value()}; + const network::response_with_id resp{call_rv.value()}; LOGGER_EVAL(resp.error_code(), INFO, ERROR, - "rpc id: {} name: {} from: {} <= " - "body: {{retval: {}, pfs_id: {}}} [op_id: {}]", - rpc_id, std::quoted("ADM_"s + __FUNCTION__), - std::quoted(endp.address()), resp.error_code(), - resp.value(), resp.op_id()); + "rpc {:>} body: {{retval: {}, pfs_id: {}}} [op_id: {}]", + rpc, resp.error_code(), resp.value(), resp.op_id()); if(const auto ec = resp.error_code(); !ec) { return tl::make_unexpected(ec); @@ -370,32 +322,26 @@ scord::error_code update_pfs_storage(const server& srv, const pfs_storage& pfs_storage, const scord::pfs_storage::ctx& new_ctx) { - scord::network::client rpc_client{srv.protocol()}; + network::client rpc_client{srv.protocol()}; - const auto rpc_id = ::api::remote_procedure::new_id(); + const auto rpc = network::rpc_info::create(RPC_NAME(), srv.address()); if(const auto& lookup_rv = rpc_client.lookup(srv.address()); lookup_rv.has_value()) { const auto& endp = lookup_rv.value(); - LOGGER_INFO("rpc id: {} name: {} from: {} => " - "body: {{pfs_id: {}, new_ctx: {}}}", - rpc_id, std::quoted("ADM_"s + __FUNCTION__), - std::quoted(rpc_client.self_address()), pfs_storage.id(), - new_ctx); + LOGGER_INFO("rpc {:<} body: {{pfs_id: {}, new_ctx: {}}}", rpc, + pfs_storage.id(), new_ctx); if(const auto& call_rv = - endp.call("ADM_"s + __FUNCTION__, pfs_storage.id(), new_ctx); + endp.call(rpc.name(), pfs_storage.id(), new_ctx); call_rv.has_value()) { - const scord::network::generic_response resp{call_rv.value()}; + const network::generic_response resp{call_rv.value()}; LOGGER_EVAL(resp.error_code(), INFO, ERROR, - "rpc id: {} name: {} from: {} <= " - "body: {{retval: {}}} [op_id: {}]", - rpc_id, std::quoted("ADM_"s + __FUNCTION__), - std::quoted(endp.address()), resp.error_code(), - resp.op_id()); + "rpc {:>} body: {{retval: {}}} [op_id: {}]", rpc, + resp.error_code(), resp.op_id()); return resp.error_code(); } @@ -408,31 +354,24 @@ update_pfs_storage(const server& srv, const pfs_storage& pfs_storage, scord::error_code remove_pfs_storage(const server& srv, const pfs_storage& pfs_storage) { - scord::network::client rpc_client{srv.protocol()}; + network::client rpc_client{srv.protocol()}; - const auto rpc_id = ::api::remote_procedure::new_id(); + const auto rpc = network::rpc_info::create(RPC_NAME(), srv.address()); if(const auto& lookup_rv = rpc_client.lookup(srv.address()); lookup_rv.has_value()) { const auto& endp = lookup_rv.value(); - LOGGER_INFO("rpc id: {} name: {} from: {} => " - "body: {{pfs_id: {}}}", - rpc_id, std::quoted("ADM_"s + __FUNCTION__), - std::quoted(rpc_client.self_address()), pfs_storage.id()); + LOGGER_INFO("rpc {:<} body: {{pfs_id: {}}}", rpc, pfs_storage.id()); - if(const auto& call_rv = - endp.call("ADM_"s + __FUNCTION__, pfs_storage.id()); + if(const auto& call_rv = endp.call(rpc.name(), pfs_storage.id()); call_rv.has_value()) { - const scord::network::generic_response resp{call_rv.value()}; + const network::generic_response resp{call_rv.value()}; LOGGER_EVAL(resp.error_code(), INFO, ERROR, - "rpc id: {} name: {} from: {} <= " - "body: {{retval: {}}} [op_id: {}]", - rpc_id, std::quoted("ADM_"s + __FUNCTION__), - std::quoted(endp.address()), resp.error_code(), - resp.op_id()); + "rpc {:>} body: {{retval: {}}} [op_id: {}]", rpc, + resp.error_code(), resp.op_id()); return resp.error_code(); } @@ -445,31 +384,24 @@ remove_pfs_storage(const server& srv, const pfs_storage& pfs_storage) { scord::error_code deploy_adhoc_storage(const server& srv, const adhoc_storage& adhoc_storage) { - scord::network::client rpc_client{srv.protocol()}; + network::client rpc_client{srv.protocol()}; - const auto rpc_id = ::api::remote_procedure::new_id(); + const auto rpc = network::rpc_info::create(RPC_NAME(), srv.address()); if(const auto& lookup_rv = rpc_client.lookup(srv.address()); lookup_rv.has_value()) { const auto& endp = lookup_rv.value(); - LOGGER_INFO("rpc id: {} name: {} from: {} => " - "body: {{adhoc_id: {}}}", - rpc_id, std::quoted("ADM_"s + __FUNCTION__), - std::quoted(rpc_client.self_address()), adhoc_storage.id()); + LOGGER_INFO("rpc {:<} body: {{adhoc_id: {}}}", rpc, adhoc_storage.id()); - if(const auto& call_rv = - endp.call("ADM_"s + __FUNCTION__, adhoc_storage.id()); + if(const auto& call_rv = endp.call(rpc.name(), adhoc_storage.id()); call_rv.has_value()) { - const scord::network::generic_response resp{call_rv.value()}; + const network::generic_response resp{call_rv.value()}; LOGGER_EVAL(resp.error_code(), INFO, ERROR, - "rpc id: {} name: {} from: {} <= " - "body: {{retval: {}}} [op_id: {}]", - rpc_id, std::quoted("ADM_"s + __FUNCTION__), - std::quoted(endp.address()), resp.error_code(), - resp.op_id()); + "rpc {:>} body: {{retval: {}}} [op_id: {}]", rpc, + resp.error_code(), resp.op_id()); return resp.error_code(); } @@ -482,31 +414,24 @@ deploy_adhoc_storage(const server& srv, const adhoc_storage& adhoc_storage) { scord::error_code tear_down_adhoc_storage(const server& srv, const adhoc_storage& adhoc_storage) { - scord::network::client rpc_client{srv.protocol()}; + network::client rpc_client{srv.protocol()}; - const auto rpc_id = ::api::remote_procedure::new_id(); + const auto rpc = network::rpc_info::create(RPC_NAME(), srv.address()); if(const auto lookup_rv = rpc_client.lookup(srv.address()); lookup_rv.has_value()) { const auto& endp = lookup_rv.value(); - LOGGER_INFO("rpc id: {} name: {} from: {} => " - "body: {{adhoc_id: {}}}", - rpc_id, std::quoted("ADM_"s + __FUNCTION__), - std::quoted(rpc_client.self_address()), adhoc_storage.id()); + LOGGER_INFO("rpc {:<} body: {{adhoc_id: {}}}", rpc, adhoc_storage.id()); - if(const auto call_rv = - endp.call("ADM_"s + __FUNCTION__, adhoc_storage.id()); + if(const auto call_rv = endp.call(rpc.name(), adhoc_storage.id()); call_rv.has_value()) { - const scord::network::generic_response resp{call_rv.value()}; + const network::generic_response resp{call_rv.value()}; LOGGER_EVAL(resp.error_code(), INFO, ERROR, - "rpc id: {} name: {} from: {} <= " - "body: {{retval: {}}} [op_id: {}]", - rpc_id, std::quoted("ADM_"s + __FUNCTION__), - std::quoted(endp.address()), resp.error_code(), - resp.op_id()); + "rpc {:>} body: {{retval: {}}} [op_id: {}]", rpc, + resp.error_code(), resp.op_id()); return resp.error_code(); } @@ -523,33 +448,27 @@ transfer_datasets(const server& srv, const job& job, const std::vector& limits, transfer::mapping mapping) { - scord::network::client rpc_client{srv.protocol()}; + network::client rpc_client{srv.protocol()}; - const auto rpc_id = ::api::remote_procedure::new_id(); + const auto rpc = network::rpc_info::create(RPC_NAME(), srv.address()); if(const auto& lookup_rv = rpc_client.lookup(srv.address()); lookup_rv.has_value()) { const auto& endp = lookup_rv.value(); - LOGGER_INFO("rpc id: {} name: {} from: {} => " - "body: {{job_id: {}, sources: {}, targets: {}, limits: {}, " - "mapping: {}}}", - rpc_id, std::quoted("ADM_"s + __FUNCTION__), - std::quoted(rpc_client.self_address()), job.id(), sources, - targets, limits, mapping); + LOGGER_INFO("rpc {:<} body: {{job_id: {}, sources: {}, targets: {}, " + "limits: {}, mapping: {}}}", + rpc, job.id(), sources, targets, limits, mapping); - if(const auto& call_rv = endp.call("ADM_"s + __FUNCTION__, job.id(), - sources, targets, limits, mapping); + if(const auto& call_rv = endp.call(rpc.name(), job.id(), sources, + targets, limits, mapping); call_rv.has_value()) { - const scord::network::response_with_id resp{call_rv.value()}; + const network::response_with_id resp{call_rv.value()}; LOGGER_EVAL(resp.error_code(), INFO, ERROR, - "rpc id: {} name: {} from: {} <= " - "body: {{retval: {}, tx_id: {}}} [op_id: {}]", - rpc_id, std::quoted("ADM_"s + __FUNCTION__), - std::quoted(endp.address()), resp.error_code(), - resp.value(), resp.op_id()); + "rpc {:>} body: {{retval: {}, tx_id: {}}} [op_id: {}]", + rpc, resp.error_code(), resp.value(), resp.op_id()); if(const auto ec = resp.error_code(); !ec) { return tl::make_unexpected(ec); diff --git a/src/lib/libscord.cpp b/src/lib/libscord.cpp index ebc0c206eab820e2f14aca0d27c9e8b3fb85eda6..909c270c4831c3a65362f220c6fbd04bfe90f77e 100644 --- a/src/lib/libscord.cpp +++ b/src/lib/libscord.cpp @@ -53,11 +53,11 @@ init_logger() { if(const auto p = std::getenv(scord::env::LOG); p && !std::string{p}.empty() && std::string{p} != "0") { if(const auto log_file = std::getenv(scord::env::LOG_OUTPUT)) { - scord::logger::create_global_logger( - "libscord", scord::logger_type::file, log_file); + logger::create_global_logger( + "libscord", logger::logger_type::file, log_file); } else { - scord::logger::create_global_logger( - "libscord", scord::logger_type::console_color); + logger::create_global_logger( + "libscord", logger::logger_type::console_color); } } } catch(const std::exception& ex) { diff --git a/src/lib/scord/types.h b/src/lib/scord/types.h index ed5bc8e01bd8f22862f3c31fbc804db6180f4d80..badda31d26fef81ad335dd862b972bbc02b36204 100644 --- a/src/lib/scord/types.h +++ b/src/lib/scord/types.h @@ -485,6 +485,8 @@ ADM_adhoc_resources_destroy(ADM_adhoc_resources_t res); * @remark ADM_ADHOC_CONTEXTs need to be freed by calling * ADM_adhoc_context_destroy(). * + * @param[in] ctl_address The address of the control node for the + * adhoc storage system * @param[in] exec_mode The adhoc storage system execution mode * @param[in] access_type The adhoc storage system execution type * @param[in] walltime The adhoc storage system walltime @@ -493,7 +495,8 @@ ADM_adhoc_resources_destroy(ADM_adhoc_resources_t res); * @return A valid ADM_ADHOC_CONTEXT if successful. NULL otherwise. */ ADM_adhoc_context_t -ADM_adhoc_context_create(ADM_adhoc_mode_t exec_mode, +ADM_adhoc_context_create(const char* ctl_address, + ADM_adhoc_mode_t exec_mode, ADM_adhoc_access_t access_type, uint32_t walltime, bool should_flush); diff --git a/src/lib/scord/types.hpp b/src/lib/scord/types.hpp index 3f0c45e71ac811d1d82d7380e2b77ab1b7cf7a38..a1002f49e8b14d455141897a62c6e76f286fe466 100644 --- a/src/lib/scord/types.hpp +++ b/src/lib/scord/types.hpp @@ -96,7 +96,7 @@ struct error_code { template void serialize(Archive&& ar) { - ar& m_value; + ar & m_value; } private: @@ -212,7 +212,7 @@ struct adhoc_storage { template void serialize(Archive&& ar) { - ar& m_nodes; + ar & m_nodes; } private: @@ -223,18 +223,18 @@ struct adhoc_storage { ctx() = default; - ctx(execution_mode exec_mode, access_type access_type, - std::uint32_t walltime, bool should_flush); + ctx(std::string controller_address, execution_mode exec_mode, + access_type access_type, std::uint32_t walltime, bool should_flush); explicit ctx(ADM_adhoc_context_t ctx); explicit operator ADM_adhoc_context_t() const; + std::string + controller_address() const; execution_mode exec_mode() const; enum access_type access_type() const; - adhoc_storage::resources - resources() const; std::uint32_t walltime() const; bool @@ -243,13 +243,15 @@ struct adhoc_storage { template void serialize(Archive&& ar) { - ar& m_exec_mode; - ar& m_access_type; - ar& m_walltime; - ar& m_should_flush; + ar & m_controller_address; + ar & m_exec_mode; + ar & m_access_type; + ar & m_walltime; + ar & m_should_flush; } private: + std::string m_controller_address; execution_mode m_exec_mode; enum access_type m_access_type; std::uint32_t m_walltime; @@ -257,10 +259,6 @@ struct adhoc_storage { }; adhoc_storage(); - adhoc_storage(enum adhoc_storage::type type, std::string name, - std::uint64_t id, execution_mode exec_mode, - access_type access_type, adhoc_storage::resources res, - std::uint32_t walltime, bool should_flush); explicit adhoc_storage(ADM_adhoc_storage_t storage); explicit operator ADM_adhoc_storage_t() const; adhoc_storage(enum adhoc_storage::type type, std::string name, @@ -326,7 +324,7 @@ struct pfs_storage { template void serialize(Archive&& ar) { - ar& m_mount_point; + ar & m_mount_point; } private: @@ -388,7 +386,7 @@ struct job { template void serialize(Archive&& ar) { - ar& m_nodes; + ar & m_nodes; } private: @@ -417,9 +415,9 @@ struct job { template void serialize(Archive& ar) { - ar& m_inputs; - ar& m_outputs; - ar& m_adhoc_storage; + ar & m_inputs; + ar & m_outputs; + ar & m_adhoc_storage; } private: @@ -820,10 +818,11 @@ struct fmt::formatter : formatter { auto format(const scord::adhoc_storage::ctx& c, FormatContext& ctx) const { - const auto str = fmt::format("{{execution_mode: {}, access_type: {}, " - "walltime: {}, should_flush: {}}}", - c.exec_mode(), c.access_type(), - c.walltime(), c.should_flush()); + const auto str = + fmt::format("{{controller: {}, execution_mode: {}, " + "access_type: {}, walltime: {}, should_flush: {}}}", + std::quoted(c.controller_address()), c.exec_mode(), + c.access_type(), c.walltime(), c.should_flush()); return formatter::format(str, ctx); } diff --git a/src/lib/types.c b/src/lib/types.c index b7480a974c709fa2cbdbcadfbd61b6b26f62a360..97c9ae12adec1647a02c8dedbfc83255140dd4d1 100644 --- a/src/lib/types.c +++ b/src/lib/types.c @@ -657,10 +657,15 @@ ADM_data_operation_destroy(ADM_data_operation_t op) { } ADM_adhoc_context_t -ADM_adhoc_context_create(ADM_adhoc_mode_t exec_mode, +ADM_adhoc_context_create(const char* ctl_address, ADM_adhoc_mode_t exec_mode, ADM_adhoc_access_t access_type, uint32_t walltime, bool should_flush) { + if(!ctl_address) { + LOGGER_ERROR("The address to the controller cannot be NULL"); + return NULL; + } + struct adm_adhoc_context* adm_adhoc_context = (struct adm_adhoc_context*) malloc(sizeof(*adm_adhoc_context)); @@ -669,6 +674,12 @@ ADM_adhoc_context_create(ADM_adhoc_mode_t exec_mode, return NULL; } + + size_t n = strlen(ctl_address); + adm_adhoc_context->c_ctl_address = + (const char*) calloc(n + 1, sizeof(char)); + strcpy((char*) adm_adhoc_context->c_ctl_address, ctl_address); + adm_adhoc_context->c_mode = exec_mode; adm_adhoc_context->c_access = access_type; adm_adhoc_context->c_walltime = walltime; diff --git a/src/lib/types.cpp b/src/lib/types.cpp index 779c1ab816eb6924ea948dd457d71ba238b18d11..b9ea9136ee3007faf1eb140f68463a916e67c588 100644 --- a/src/lib/types.cpp +++ b/src/lib/types.cpp @@ -173,20 +173,20 @@ node::serialize(Archive& ar) { // we must also explicitly instantiate our template functions for // serialization in the desired archives template void -node::impl::save( - scord::network::serialization::output_archive&) const; +node::impl::save( + network::serialization::output_archive&) const; template void -node::impl::load( - scord::network::serialization::input_archive&); +node::impl::load( + network::serialization::input_archive&); template void -node::serialize( - scord::network::serialization::output_archive&); +node::serialize( + network::serialization::output_archive&); template void -node::serialize( - scord::network::serialization::input_archive&); +node::serialize( + network::serialization::input_archive&); class job::impl { @@ -287,7 +287,9 @@ job::resources::resources(ADM_job_resources_t res) { m_nodes.reserve(res->r_nodes->l_length); for(size_t i = 0; i < res->r_nodes->l_length; ++i) { - m_nodes.emplace_back(res->r_nodes->l_nodes[i].n_hostname); + m_nodes.emplace_back(res->r_nodes->l_nodes[i].n_hostname, + static_cast( + res->r_nodes->l_nodes[i].n_type)); } } @@ -424,20 +426,20 @@ transfer::serialize(Archive& ar) { // we must also explicitly instantiate our template functions for // serialization in the desired archives template void -transfer::impl::save( - scord::network::serialization::output_archive&) const; +transfer::impl::save( + network::serialization::output_archive&) const; template void -transfer::impl::load( - scord::network::serialization::input_archive&); +transfer::impl::load( + network::serialization::input_archive&); template void -transfer::serialize( - scord::network::serialization::output_archive&); +transfer::serialize( + network::serialization::output_archive&); template void -transfer::serialize( - scord::network::serialization::input_archive&); +transfer::serialize( + network::serialization::input_archive&); class dataset::impl { public: @@ -511,20 +513,20 @@ dataset::serialize(Archive& ar) { // we must also explicitly instantiate our template functions for // serialization in the desired archives template void -dataset::impl::save( - scord::network::serialization::output_archive&) const; +dataset::impl::save( + network::serialization::output_archive&) const; template void -dataset::impl::load( - scord::network::serialization::input_archive&); +dataset::impl::load( + network::serialization::input_archive&); template void -dataset::serialize( - scord::network::serialization::output_archive&); +dataset::serialize( + network::serialization::output_archive&); template void -dataset::serialize( - scord::network::serialization::input_archive&); +dataset::serialize( + network::serialization::input_archive&); adhoc_storage::resources::resources(std::vector nodes) : m_nodes(std::move(nodes)) {} @@ -559,24 +561,33 @@ adhoc_storage::resources::nodes() const { return m_nodes; } -adhoc_storage::ctx::ctx(adhoc_storage::execution_mode exec_mode, +adhoc_storage::ctx::ctx(std::string controller_address, + adhoc_storage::execution_mode exec_mode, adhoc_storage::access_type access_type, std::uint32_t walltime, bool should_flush) - : m_exec_mode(exec_mode), m_access_type(access_type), m_walltime(walltime), + : m_controller_address(std::move(controller_address)), + m_exec_mode(exec_mode), m_access_type(access_type), m_walltime(walltime), m_should_flush(should_flush) {} adhoc_storage::ctx::ctx(ADM_adhoc_context_t ctx) - : adhoc_storage::ctx(static_cast(ctx->c_mode), + : adhoc_storage::ctx(ctx->c_ctl_address, + static_cast(ctx->c_mode), static_cast(ctx->c_access), ctx->c_walltime, ctx->c_should_bg_flush) {} adhoc_storage::ctx::operator ADM_adhoc_context_t() const { return ADM_adhoc_context_create( + m_controller_address.c_str(), static_cast(m_exec_mode), static_cast(m_access_type), m_walltime, m_should_flush); } +std::string +adhoc_storage::ctx::controller_address() const { + return m_controller_address; +} + adhoc_storage::execution_mode adhoc_storage::ctx::exec_mode() const { return m_exec_mode; @@ -656,6 +667,7 @@ public: ar(SCORD_SERIALIZATION_NVP(m_name)); ar(SCORD_SERIALIZATION_NVP(m_id)); ar(SCORD_SERIALIZATION_NVP(m_ctx)); + ar(SCORD_SERIALIZATION_NVP(m_resources)); } template @@ -665,6 +677,7 @@ public: ar(SCORD_SERIALIZATION_NVP(m_name)); ar(SCORD_SERIALIZATION_NVP(m_id)); ar(SCORD_SERIALIZATION_NVP(m_ctx)); + ar(SCORD_SERIALIZATION_NVP(m_resources)); } @@ -678,16 +691,6 @@ private: adhoc_storage::adhoc_storage() = default; -adhoc_storage::adhoc_storage(enum adhoc_storage::type type, std::string name, - std::uint64_t id, execution_mode exec_mode, - access_type access_type, - struct adhoc_storage::resources res, - std::uint32_t walltime, bool should_flush) - : m_pimpl(std::make_unique(type, std::move(name), id, - adhoc_storage::ctx{exec_mode, access_type, - walltime, should_flush}, - std::move(res))) {} - adhoc_storage::adhoc_storage(ADM_adhoc_storage_t st) : m_pimpl(std::make_unique( static_cast(st->s_type), st->s_name, @@ -768,20 +771,20 @@ adhoc_storage::serialize(Archive& ar) { // we must also explicitly instantiate our template functions for // serialization in the desired archives template void -adhoc_storage::impl::save( - scord::network::serialization::output_archive&) const; +adhoc_storage::impl::save( + network::serialization::output_archive&) const; template void -adhoc_storage::impl::load( - scord::network::serialization::input_archive&); +adhoc_storage::impl::load( + network::serialization::input_archive&); template void -adhoc_storage::serialize( - scord::network::serialization::output_archive&); +adhoc_storage::serialize( + network::serialization::output_archive&); template void -adhoc_storage::serialize( - scord::network::serialization::input_archive&); +adhoc_storage::serialize( + network::serialization::input_archive&); adhoc_storage::~adhoc_storage() = default; @@ -941,20 +944,20 @@ pfs_storage::serialize(Archive& ar) { // we must also explicitly instantiate our template functions for // serialization in the desired archives template void -pfs_storage::impl::save( - scord::network::serialization::output_archive&) const; +pfs_storage::impl::save( + network::serialization::output_archive&) const; template void -pfs_storage::impl::load( - scord::network::serialization::input_archive&); +pfs_storage::impl::load( + network::serialization::input_archive&); template void -pfs_storage::serialize( - scord::network::serialization::output_archive&); +pfs_storage::serialize( + network::serialization::output_archive&); template void -pfs_storage::serialize( - scord::network::serialization::input_archive&); +pfs_storage::serialize( + network::serialization::input_archive&); namespace qos { @@ -1090,20 +1093,20 @@ entity::serialize(Archive& ar) { // we must also explicitly instantiate our template functions for // serialization in the desired archives template void -entity::impl::save( - scord::network::serialization::output_archive&) const; +entity::impl::save( + network::serialization::output_archive&) const; template void -entity::impl::load( - scord::network::serialization::input_archive&); +entity::impl::load( + network::serialization::input_archive&); template void -entity::serialize( - scord::network::serialization::output_archive&); +entity::serialize( + network::serialization::output_archive&); template void -entity::serialize( - scord::network::serialization::input_archive&); +entity::serialize( + network::serialization::input_archive&); class limit::impl { @@ -1218,20 +1221,20 @@ limit::serialize(Archive& ar) { // we must also explicitly instantiate our template functions for // serialization in the desired archives template void -limit::impl::save( - scord::network::serialization::output_archive&) const; +limit::impl::save( + network::serialization::output_archive&) const; template void -limit::impl::load( - scord::network::serialization::input_archive&); +limit::impl::load( + network::serialization::input_archive&); template void -limit::serialize( - scord::network::serialization::output_archive&); +limit::serialize( + network::serialization::output_archive&); template void -limit::serialize( - scord::network::serialization::input_archive&); +limit::serialize( + network::serialization::input_archive&); } // namespace qos diff --git a/src/lib/types_private.h b/src/lib/types_private.h index b66b0b722acf31649cadaa8762fc4fbb64a53de6..3fda9e61877a998f3aa8e2fa0d72fb78374582f0 100644 --- a/src/lib/types_private.h +++ b/src/lib/types_private.h @@ -76,6 +76,8 @@ struct adm_dataset_info { }; struct adm_adhoc_context { + /** The address to the node responsible for this adhoc storage system */ + const char* c_ctl_address; /** The adhoc storage system execution mode */ ADM_adhoc_mode_t c_mode; /** The adhoc storage system access type */ diff --git a/src/scord-ctl/CMakeLists.txt b/src/scord-ctl/CMakeLists.txt index c36639189191bfc966aa9f04db0cd8075bef7d72..9654c6e364549cc4a29b55b035c54db8e46864b2 100644 --- a/src/scord-ctl/CMakeLists.txt +++ b/src/scord-ctl/CMakeLists.txt @@ -26,7 +26,7 @@ add_executable(scord-ctl) target_sources( - scord-ctl PRIVATE scord-ctl.cpp rpc_handlers.hpp rpc_handlers.cpp + scord-ctl PRIVATE scord_ctl.cpp rpc_server.cpp rpc_server.hpp ) target_include_directories( diff --git a/src/scord-ctl/rpc_handlers.cpp b/src/scord-ctl/rpc_handlers.cpp deleted file mode 100644 index c021a46615f5f99885d3ea71d4b1ec55396bf5e6..0000000000000000000000000000000000000000 --- a/src/scord-ctl/rpc_handlers.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/****************************************************************************** - * Copyright 2021-2022, 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 scord. - * - * scord 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. - * - * scord 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 scord. If not, see . - * - * SPDX-License-Identifier: GPL-3.0-or-later - *****************************************************************************/ - -#include -#include -#include "rpc_handlers.hpp" - -struct remote_procedure { - static std::uint64_t - new_id() { - static std::atomic_uint64_t current_id; - return current_id++; - } -}; - -namespace scord::network::handlers { - -void -ping(const scord::network::request& req) { - - using scord::network::generic_response; - using scord::network::get_address; - - const auto rpc_id = remote_procedure::new_id(); - - LOGGER_INFO("rpc id: {} name: {} from: {} => " - "body: {{}}", - rpc_id, std::quoted(__FUNCTION__), - std::quoted(get_address(req))); - - const auto resp = generic_response{rpc_id, scord::error_code::success}; - - LOGGER_INFO("rpc id: {} name: {} to: {} <= " - "body: {{retval: {}}}", - rpc_id, std::quoted(__FUNCTION__), - std::quoted(get_address(req)), scord::error_code::success); - - req.respond(resp); -} - -} // namespace scord::network::handlers diff --git a/src/scord-ctl/rpc_server.cpp b/src/scord-ctl/rpc_server.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bb7da914262c69defecb9430dd8b6f3c38960110 --- /dev/null +++ b/src/scord-ctl/rpc_server.cpp @@ -0,0 +1,154 @@ +/****************************************************************************** + * Copyright 2021-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 scord. + * + * scord 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. + * + * scord 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 scord. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + *****************************************************************************/ + +#include +#include +#include +#include "rpc_server.hpp" + +// required for ::waitpid() +#include +#include + +using namespace std::literals; + +namespace scord_ctl { + +rpc_server::rpc_server(std::string name, std::string address, bool daemonize, + std::filesystem::path rundir) + : server::server(std::move(name), std::move(address), std::move(daemonize), + std::move(rundir)), + provider::provider(m_network_engine, 0) { + +#define EXPAND(rpc_name) "ADM_" #rpc_name##s, &rpc_server::rpc_name + + provider::define(EXPAND(ping)); + provider::define(EXPAND(deploy_adhoc_storage)); + +#undef EXPAND +} + +#define RPC_NAME() ("ADM_"s + __FUNCTION__) + +void +rpc_server::ping(const network::request& req) { + + using network::generic_response; + using network::get_address; + using network::rpc_info; + + const auto rpc = rpc_info::create(RPC_NAME(), get_address(req)); + + LOGGER_INFO("rpc {:>} body: {{}}", rpc); + + const auto resp = generic_response{rpc.id(), scord::error_code::success}; + + LOGGER_INFO("rpc {:<} body: {{retval: {}}}", rpc, + scord::error_code::success); + + req.respond(resp); +} + +void +rpc_server::deploy_adhoc_storage( + const network::request& req, + const enum scord::adhoc_storage::type adhoc_type, + const scord::adhoc_storage::ctx& adhoc_ctx, + const scord::adhoc_storage::resources& adhoc_resources) { + + using network::generic_response; + using network::get_address; + using network::rpc_info; + + const auto rpc = rpc_info::create(RPC_NAME(), get_address(req)); + + LOGGER_INFO("rpc {:>} body: {{type: {}, ctx: {}, resources: {}}}", rpc, + adhoc_type, adhoc_ctx, adhoc_resources); + + auto ec = scord::error_code::success; + + if(adhoc_type == scord::adhoc_storage::type::gekkofs) { + /* Number of nodes */ + const std::string nodes = + std::to_string(adhoc_resources.nodes().size()); + + /* Walltime */ + const std::string walltime = std::to_string(adhoc_ctx.walltime()); + + /* Launch script */ + switch(const auto pid = fork()) { + case 0: { + std::vector args; + args.push_back("gkfs"); + // args.push_back("-c"); + // args.push_back("gkfs.conf"); + args.push_back("-n"); + args.push_back(nodes.c_str()); + // args.push_back("-w"); + // args.push_back(walltime.c_str()); + args.push_back("--srun"); + args.push_back("start"); + args.push_back(NULL); + std::vector env; + env.push_back(NULL); + + execvpe("gkfs", const_cast(args.data()), + const_cast(env.data())); + LOGGER_INFO("ADM_deploy_adhoc_storage() script didn't execute"); + exit(EXIT_FAILURE); + break; + } + case -1: { + ec = scord::error_code::other; + LOGGER_ERROR("rpc {:<} body: {{retval: {}}}", rpc, ec); + break; + } + default: { + int wstatus = 0; + pid_t retwait = ::waitpid(pid, &wstatus, 0); + if(retwait == -1) { + LOGGER_ERROR( + "rpc id: {} error_msg: \"Error waitpid code: {}\"", + rpc.id(), retwait); + ec = scord::error_code::other; + } else { + if(WEXITSTATUS(wstatus) != 0) { + ec = scord::error_code::other; + } else { + ec = scord::error_code::success; + } + } + break; + } + } + } + + const auto resp = generic_response{rpc.id(), ec}; + + LOGGER_INFO("rpc {:<} body: {{retval: {}}}", rpc, ec); + + req.respond(resp); +} + +} // namespace scord_ctl diff --git a/src/scord-ctl/rpc_handlers.hpp b/src/scord-ctl/rpc_server.hpp similarity index 57% rename from src/scord-ctl/rpc_handlers.hpp rename to src/scord-ctl/rpc_server.hpp index a896d794450e89ad51687f839c48bf2a89b893cf..2988a1c4f3f4f565927574bf7764f9cf4bcd7497 100644 --- a/src/scord-ctl/rpc_handlers.hpp +++ b/src/scord-ctl/rpc_server.hpp @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright 2021-2022, Barcelona Supercomputing Center (BSC), Spain + * Copyright 2021-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). @@ -22,18 +22,34 @@ * SPDX-License-Identifier: GPL-3.0-or-later *****************************************************************************/ -#ifndef SCORD_CTL_RPC_HANDLERS_HPP -#define SCORD_CTL_RPC_HANDLERS_HPP -#include -#include +#ifndef SCORD_CTL_RPC_SERVER_HPP +#define SCORD_CTL_RPC_SERVER_HPP + +#include #include -namespace scord::network::handlers { +namespace scord_ctl { + +class rpc_server : public network::server, + public network::provider { + +public: + rpc_server(std::string name, std::string address, bool daemonize, + std::filesystem::path rundir); + +private: + void + ping(const network::request& req); -void -ping(const scord::network::request& req); + void + deploy_adhoc_storage( + const network::request& req, + enum scord::adhoc_storage::type adhoc_type, + const scord::adhoc_storage::ctx& adhoc_ctx, + const scord::adhoc_storage::resources& adhoc_resources); +}; -} // namespace scord::network::handlers +} // namespace scord_ctl -#endif // SCORD_CTL_RPC_HANDLERS_HPP +#endif // SCORD_SCORD_CTL_RPC_SERVER_HPP diff --git a/src/scord-ctl/scord-ctl.cpp b/src/scord-ctl/scord_ctl.cpp similarity index 84% rename from src/scord-ctl/scord-ctl.cpp rename to src/scord-ctl/scord_ctl.cpp index ab2d1e0fa9b6c3e1ed80f7b34c01ccfea3ab1a85..b9c0286be6f952de54928575a9d02789ab6922f9 100644 --- a/src/scord-ctl/scord-ctl.cpp +++ b/src/scord-ctl/scord_ctl.cpp @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright 2021, Barcelona Supercomputing Center (BSC), Spain + * Copyright 2021-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). @@ -31,8 +31,7 @@ #include #include -#include -#include "rpc_handlers.hpp" +#include "rpc_server.hpp" namespace fs = std::filesystem; using namespace std::literals; @@ -76,21 +75,12 @@ main(int argc, char* argv[]) { CLI11_PARSE(app, argc, argv); try { - scord::network::server srv(progname, cli_args.address, false, - fs::current_path()); + scord_ctl::rpc_server srv(progname, cli_args.address, false, + fs::current_path()); if(cli_args.output_file) { - srv.configure_logger(scord::logger_type::file, + srv.configure_logger(logger::logger_type::file, *cli_args.output_file); } - -// convenience macro to ensure the names of an RPC and its handler -// always match -#define EXPAND(rpc_name) "ADM_" #rpc_name##s, scord::network::handlers::rpc_name - - srv.set_handler(EXPAND(ping)); - -#undef EXPAND - return srv.run(); } catch(const std::exception& ex) { fmt::print(stderr, diff --git a/src/scord/CMakeLists.txt b/src/scord/CMakeLists.txt index b79e3fbaf382196fa3852add1df98ad184f15203..5ccfb19ebfa0bd0d6e35fd7835bb90639ace92c2 100644 --- a/src/scord/CMakeLists.txt +++ b/src/scord/CMakeLists.txt @@ -25,9 +25,10 @@ # scord daemon add_executable(scord) -target_sources(scord PRIVATE scord.cpp rpc_handlers.hpp - rpc_handlers.cpp job_manager.hpp adhoc_storage_manager.hpp - pfs_storage_manager.hpp ${CMAKE_CURRENT_BINARY_DIR}/defaults.hpp) +target_sources(scord PRIVATE scord.cpp + job_manager.hpp adhoc_storage_manager.hpp + pfs_storage_manager.hpp ${CMAKE_CURRENT_BINARY_DIR}/defaults.hpp + internal_types.hpp internal_types.cpp rpc_server.hpp rpc_server.cpp) configure_file(defaults.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/defaults.hpp @ONLY) diff --git a/src/scord/adhoc_storage_manager.hpp b/src/scord/adhoc_storage_manager.hpp index 381991a698497652efd5b2cdc0bced505de84d6c..848248b207d7a1d94964aa61da54f201dbc9ceb9 100644 --- a/src/scord/adhoc_storage_manager.hpp +++ b/src/scord/adhoc_storage_manager.hpp @@ -28,7 +28,6 @@ #include #include -#include #include #include #include @@ -38,7 +37,7 @@ namespace scord { -struct adhoc_storage_manager : scord::utils::singleton { +struct adhoc_storage_manager { tl::expected, scord::error_code> @@ -144,9 +143,6 @@ struct adhoc_storage_manager : scord::utils::singleton { private: - friend class scord::utils::singleton; - adhoc_storage_manager() = default; - mutable abt::shared_mutex m_adhoc_storages_mutex; std::unordered_map> diff --git a/src/scord/internal_types.cpp b/src/scord/internal_types.cpp new file mode 100644 index 0000000000000000000000000000000000000000..599edae1651ba4a65b8559624ad15b74d12e4bb4 --- /dev/null +++ b/src/scord/internal_types.cpp @@ -0,0 +1,107 @@ +/****************************************************************************** + * Copyright 2021-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 scord. + * + * scord 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. + * + * scord 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 scord. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + *****************************************************************************/ + +#include +#include +#include "internal_types.hpp" + + +namespace scord::internal { + +job_info::job_info(scord::job job, scord::job::resources resources, + scord::job::requirements requirements) + : m_job(std::move(job)), m_resources(std::move(resources)), + m_requirements(std::move(requirements)) {} + +scord::job +job_info::job() const { + return m_job; +} + +std::optional +job_info::resources() const { + return m_resources; +} + +void +job_info::update(scord::job::resources resources) { + m_resources = std::move(resources); +} + +adhoc_storage_info::adhoc_storage_info(scord::adhoc_storage adhoc_storage) + : m_adhoc_storage(std::move(adhoc_storage)) {} + +scord::adhoc_storage +adhoc_storage_info::adhoc_storage() const { + return m_adhoc_storage; +} + +void +adhoc_storage_info::update(scord::adhoc_storage::resources new_resources) { + m_adhoc_storage.update(std::move(new_resources)); +} + +scord::error_code +adhoc_storage_info::add_client_info( + std::shared_ptr job_info) { + + scord::abt::unique_lock lock(m_info_mutex); + + if(m_client_info) { + LOGGER_ERROR("adhoc storage {} already has a client", + m_adhoc_storage.id()); + return error_code::adhoc_in_use; + } + + m_client_info = std::move(job_info); + + return error_code::success; +} + +void +adhoc_storage_info::remove_client_info() { + scord::abt::unique_lock lock(m_info_mutex); + m_client_info.reset(); +} + +std::shared_ptr +adhoc_storage_info::client_info() const { + scord::abt::shared_lock lock(m_info_mutex); + return m_client_info; +} + +pfs_storage_info::pfs_storage_info(scord::pfs_storage pfs_storage) + : m_pfs_storage(std::move(pfs_storage)) {} + +scord::pfs_storage +pfs_storage_info::pfs_storage() const { + return m_pfs_storage; +} + +void +pfs_storage_info::update(scord::pfs_storage::ctx pfs_context) { + m_pfs_storage.update(std::move(pfs_context)); +} + +} // namespace scord::internal diff --git a/src/scord/internal_types.hpp b/src/scord/internal_types.hpp index 72d34e4d0371df1929e6294bf8fddbb13bd5b123..f6b3948f9a7066fb1521e8418bfe41ae3c027c26 100644 --- a/src/scord/internal_types.hpp +++ b/src/scord/internal_types.hpp @@ -26,27 +26,22 @@ #ifndef SCORD_INTERNAL_TYPES_HPP #define SCORD_INTERNAL_TYPES_HPP -#include +#include +#include +#include namespace scord::internal { struct job_info { - explicit job_info(scord::job job) : m_job(std::move(job)) {} job_info(scord::job job, scord::job::resources resources, - scord::job::requirements requirements) - : m_job(std::move(job)), m_resources(std::move(resources)), - m_requirements(std::move(requirements)) {} + scord::job::requirements requirements); scord::job - job() const { - return m_job; - } + job() const; std::optional - resources() const { - return m_resources; - } + resources() const; std::optional requirements() const { @@ -54,9 +49,7 @@ struct job_info { } void - update(scord::job::resources resources) { - m_resources = std::move(resources); - } + update(scord::job::resources resources); scord::job m_job; std::optional m_resources; @@ -65,46 +58,22 @@ struct job_info { struct adhoc_storage_info { - explicit adhoc_storage_info(scord::adhoc_storage adhoc_storage) - : m_adhoc_storage(std::move(adhoc_storage)) {} + explicit adhoc_storage_info(scord::adhoc_storage adhoc_storage); scord::adhoc_storage - adhoc_storage() const { - return m_adhoc_storage; - } + adhoc_storage() const; void - update(scord::adhoc_storage::resources new_resources) { - m_adhoc_storage.update(std::move(new_resources)); - } + update(scord::adhoc_storage::resources new_resources); scord::error_code - add_client_info(std::shared_ptr job_info) { - - scord::abt::unique_lock lock(m_info_mutex); - - if(m_client_info) { - LOGGER_ERROR("adhoc storage {} already has a client", - m_adhoc_storage.id()); - return error_code::adhoc_in_use; - } - - m_client_info = std::move(job_info); - - return error_code::success; - } + add_client_info(std::shared_ptr job_info); void - remove_client_info() { - scord::abt::unique_lock lock(m_info_mutex); - m_client_info.reset(); - } + remove_client_info(); std::shared_ptr - client_info() const { - scord::abt::shared_lock lock(m_info_mutex); - return m_client_info; - } + client_info() const; scord::adhoc_storage m_adhoc_storage; std::shared_ptr m_client_info; @@ -113,18 +82,13 @@ struct adhoc_storage_info { struct pfs_storage_info { - explicit pfs_storage_info(scord::pfs_storage pfs_storage) - : m_pfs_storage(std::move(pfs_storage)) {} + explicit pfs_storage_info(scord::pfs_storage pfs_storage); scord::pfs_storage - pfs_storage() const { - return m_pfs_storage; - } + pfs_storage() const; void - update(scord::pfs_storage::ctx pfs_context) { - m_pfs_storage.update(std::move(pfs_context)); - } + update(scord::pfs_storage::ctx pfs_context); scord::pfs_storage m_pfs_storage; std::shared_ptr m_client_info; diff --git a/src/scord/job_manager.hpp b/src/scord/job_manager.hpp index cf9da9c21fa826f5ac8d68da526946c571d26bfb..17feef77baae6152be5ed7b412752a4c4a89f6d1 100644 --- a/src/scord/job_manager.hpp +++ b/src/scord/job_manager.hpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -37,8 +36,7 @@ namespace scord { - -struct job_manager : scord::utils::singleton { +struct job_manager { tl::expected, scord::error_code> create(scord::slurm_job_id slurm_id, scord::job::resources job_resources, @@ -112,9 +110,6 @@ struct job_manager : scord::utils::singleton { } private: - friend class scord::utils::singleton; - job_manager() = default; - mutable abt::shared_mutex m_jobs_mutex; std::unordered_map> diff --git a/src/scord/pfs_storage_manager.hpp b/src/scord/pfs_storage_manager.hpp index de02184829f3397ac74a0ce961eff491321078cd..a5bb0548de36c1b3ad8ddacdd0637975f5849361 100644 --- a/src/scord/pfs_storage_manager.hpp +++ b/src/scord/pfs_storage_manager.hpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -37,7 +36,7 @@ namespace scord { -struct pfs_storage_manager : scord::utils::singleton { +struct pfs_storage_manager { tl::expected, scord::error_code> @@ -117,9 +116,6 @@ struct pfs_storage_manager : scord::utils::singleton { } private: - friend class scord::utils::singleton; - pfs_storage_manager() = default; - mutable abt::shared_mutex m_pfs_storages_mutex; std::unordered_map> diff --git a/src/scord/rpc_handlers.cpp b/src/scord/rpc_handlers.cpp deleted file mode 100644 index 329f4c716b9eaeb6ce9e932257e1f0ea4601432d..0000000000000000000000000000000000000000 --- a/src/scord/rpc_handlers.cpp +++ /dev/null @@ -1,568 +0,0 @@ -/****************************************************************************** - * Copyright 2021-2022, 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 scord. - * - * scord 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. - * - * scord 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 scord. If not, see . - * - * SPDX-License-Identifier: GPL-3.0-or-later - *****************************************************************************/ - -#include -#include -#include "rpc_handlers.hpp" -#include "job_manager.hpp" -#include "adhoc_storage_manager.hpp" -#include "pfs_storage_manager.hpp" - -// Process running -#include -#include - -using namespace std::literals; - -struct remote_procedure { - static std::uint64_t - new_id() { - static std::atomic_uint64_t current_id; - return current_id++; - } -}; - -namespace scord::network::handlers { - -void -ping(const scord::network::request& req) { - - using scord::network::generic_response; - using scord::network::get_address; - - const auto rpc_name = "ADM_"s + __FUNCTION__; - const auto rpc_id = remote_procedure::new_id(); - - LOGGER_INFO("rpc id: {} name: {} from: {} => " - "body: {{}}", - rpc_id, std::quoted(rpc_name), std::quoted(get_address(req))); - - const auto resp = generic_response{rpc_id, scord::error_code::success}; - - LOGGER_INFO("rpc id: {} name: {} to: {} <= " - "body: {{retval: {}}}", - rpc_id, std::quoted(rpc_name), std::quoted(get_address(req)), - scord::error_code::success); - - req.respond(resp); -} - -void -register_job(const scord::network::request& req, - const scord::job::resources& job_resources, - const scord::job::requirements& job_requirements, - scord::slurm_job_id slurm_id) { - - using scord::network::get_address; - - const auto rpc_name = "ADM_"s + __FUNCTION__; - const auto rpc_id = remote_procedure::new_id(); - - LOGGER_INFO("rpc id: {} name: {} from: {} => " - "body: {{job_resources: {}, job_requirements: {}, slurm_id: " - "{}}}", - rpc_id, std::quoted(rpc_name), std::quoted(get_address(req)), - job_resources, job_requirements, slurm_id); - - scord::error_code ec; - std::optional job_id; - auto& jm = scord::job_manager::instance(); - - if(const auto jm_result = - jm.create(slurm_id, job_resources, job_requirements); - jm_result.has_value()) { - - const auto& job_info = jm_result.value(); - - // if the job requires an adhoc storage instance, inform the appropriate - // adhoc_storage instance (if registered) - if(job_requirements.adhoc_storage()) { - const auto adhoc_id = job_requirements.adhoc_storage()->id(); - auto& adhoc_manager = scord::adhoc_storage_manager::instance(); - ec = adhoc_manager.add_client_info(adhoc_id, job_info); - } - - job_id = job_info->job().id(); - } else { - LOGGER_ERROR("rpc id: {} error_msg: \"Error creating job: {}\"", rpc_id, - jm_result.error()); - ec = jm_result.error(); - } - - const auto resp = response_with_id{rpc_id, ec, job_id}; - - LOGGER_INFO("rpc id: {} name: {} to: {} <= " - "body: {{retval: {}, job_id: {}}}", - rpc_id, std::quoted(rpc_name), std::quoted(get_address(req)), - ec, job_id); - - req.respond(resp); -} - -void -update_job(const request& req, scord::job_id job_id, - const scord::job::resources& new_resources) { - - using scord::network::get_address; - - const auto rpc_name = "ADM_"s + __FUNCTION__; - const auto rpc_id = remote_procedure::new_id(); - - LOGGER_INFO("rpc id: {} name: {} from: {} => " - "body: {{job_id: {}, new_resources: {}}}", - rpc_id, std::quoted(rpc_name), std::quoted(get_address(req)), - job_id, new_resources); - - auto& jm = scord::job_manager::instance(); - const auto ec = jm.update(job_id, new_resources); - - if(!ec) { - LOGGER_ERROR("rpc id: {} error_msg: \"Error updating job: {}\"", rpc_id, - ec); - } - - const auto resp = generic_response{rpc_id, ec}; - - LOGGER_INFO("rpc id: {} name: {} to: {} <= " - "body: {{retval: {}}}", - rpc_id, std::quoted(rpc_name), std::quoted(get_address(req)), - ec); - - req.respond(resp); -} - -void -remove_job(const request& req, scord::job_id job_id) { - - using scord::network::get_address; - - const auto rpc_name = "ADM_"s + __FUNCTION__; - const auto rpc_id = remote_procedure::new_id(); - - LOGGER_INFO("rpc id: {} name: {} from: {} => " - "body: {{job_id: {}}}", - rpc_id, std::quoted(rpc_name), std::quoted(get_address(req)), - job_id); - - scord::error_code ec; - auto& jm = scord::job_manager::instance(); - const auto jm_result = jm.remove(job_id); - - if(jm_result) { - // if the job was using an adhoc storage instance, inform the - // appropriate adhoc_storage that the job is no longer its client - const auto& job_info = jm_result.value(); - - if(const auto adhoc_storage = job_info->requirements()->adhoc_storage(); - adhoc_storage.has_value()) { - auto& adhoc_manager = scord::adhoc_storage_manager::instance(); - ec = adhoc_manager.remove_client_info(adhoc_storage->id()); - } - } else { - LOGGER_ERROR("rpc id: {} error_msg: \"Error removing job: {}\"", rpc_id, - job_id); - ec = jm_result.error(); - } - - const auto resp = generic_response{rpc_id, ec}; - - LOGGER_INFO("rpc id: {} name: {} to: {} <= " - "body: {{retval: {}}}", - rpc_id, std::quoted(rpc_name), std::quoted(get_address(req)), - ec); - - req.respond(resp); -} - -void -register_adhoc_storage(const request& req, const std::string& name, - enum scord::adhoc_storage::type type, - const scord::adhoc_storage::ctx& ctx, - const scord::adhoc_storage::resources& resources) { - - using scord::network::get_address; - - const auto rpc_name = "ADM_"s + __FUNCTION__; - const auto rpc_id = remote_procedure::new_id(); - - LOGGER_INFO("rpc id: {} name: {} from: {} => " - "body: {{name: {}, type: {}, adhoc_ctx: {}, " - "adhoc_resources: {}}}", - rpc_id, std::quoted(rpc_name), std::quoted(get_address(req)), - name, type, ctx, resources); - - scord::error_code ec; - std::optional adhoc_id; - auto& adhoc_manager = scord::adhoc_storage_manager::instance(); - - if(const auto am_result = adhoc_manager.create(type, name, ctx, resources); - am_result.has_value()) { - const auto& adhoc_storage_info = am_result.value(); - adhoc_id = adhoc_storage_info->adhoc_storage().id(); - } else { - LOGGER_ERROR("rpc id: {} error_msg: \"Error creating adhoc_storage: " - "{}\"", - rpc_id, am_result.error()); - ec = am_result.error(); - } - - const auto resp = response_with_id{rpc_id, ec, adhoc_id}; - - LOGGER_INFO("rpc id: {} name: {} to: {} <= " - "body: {{retval: {}, adhoc_id: {}}}", - rpc_id, std::quoted(rpc_name), std::quoted(get_address(req)), - ec, adhoc_id); - - req.respond(resp); -} - -void -update_adhoc_storage(const request& req, std::uint64_t adhoc_id, - const scord::adhoc_storage::resources& new_resources) { - - using scord::network::get_address; - - const auto rpc_name = "ADM_"s + __FUNCTION__; - const auto rpc_id = remote_procedure::new_id(); - - LOGGER_INFO("rpc id: {} name: {} from: {} => " - "body: {{adhoc_id: {}, new_resources: {}}}", - rpc_id, std::quoted(rpc_name), std::quoted(get_address(req)), - adhoc_id, new_resources); - - auto& adhoc_manager = scord::adhoc_storage_manager::instance(); - const auto ec = adhoc_manager.update(adhoc_id, new_resources); - - if(!ec) { - LOGGER_ERROR( - "rpc id: {} error_msg: \"Error updating adhoc_storage: {}\"", - rpc_id, ec); - } - - const auto resp = generic_response{rpc_id, ec}; - - LOGGER_INFO("rpc id: {} name: {} to: {} <= " - "body: {{retval: {}}}", - rpc_id, std::quoted(rpc_name), std::quoted(get_address(req)), - ec); - - req.respond(resp); -} - -void -remove_adhoc_storage(const request& req, std::uint64_t adhoc_id) { - - using scord::network::get_address; - - const auto rpc_name = "ADM_"s + __FUNCTION__; - const auto rpc_id = remote_procedure::new_id(); - - LOGGER_INFO("rpc id: {} name: {} from: {} => " - "body: {{adhoc_id: {}}}", - rpc_id, std::quoted(rpc_name), std::quoted(get_address(req)), - adhoc_id); - - auto& adhoc_manager = scord::adhoc_storage_manager::instance(); - scord::error_code ec = adhoc_manager.remove(adhoc_id); - - if(!ec) { - LOGGER_ERROR("rpc id: {} error_msg: \"Error removing job: {}\"", rpc_id, - adhoc_id); - } - - const auto resp = generic_response{rpc_id, ec}; - - LOGGER_INFO("rpc id: {} name: {} to: {} <= " - "body: {{retval: {}}}", - rpc_id, std::quoted(rpc_name), std::quoted(get_address(req)), - ec); - - req.respond(resp); -} - -void -deploy_adhoc_storage(const request& req, std::uint64_t adhoc_id) { - - using scord::network::get_address; - - const auto rpc_name = "ADM_"s + __FUNCTION__; - const auto rpc_id = remote_procedure::new_id(); - - LOGGER_INFO("rpc id: {} name: {} from: {} => " - "body: {{adhoc_id: {}}}", - rpc_id, std::quoted(rpc_name), std::quoted(get_address(req)), - adhoc_id); - - auto ec = scord::error_code::success; - auto& adhoc_manager = scord::adhoc_storage_manager::instance(); - - if(const auto am_result = adhoc_manager.find(adhoc_id); - am_result.has_value()) { - const auto& storage_info = am_result.value(); - const auto adhoc_storage = storage_info->adhoc_storage(); - - if(adhoc_storage.type() == scord::adhoc_storage::type::gekkofs) { - const auto adhoc_ctx = adhoc_storage.context(); - /* Number of nodes */ - const std::string nodes = std::to_string( - adhoc_storage.get_resources().nodes().size()); - - /* Walltime */ - const std::string walltime = std::to_string(adhoc_ctx.walltime()); - - /* Launch script */ - switch(const auto pid = fork()) { - case 0: { - std::vector args; - args.push_back("gkfs"); - // args.push_back("-c"); - // args.push_back("gkfs.conf"); - args.push_back("-n"); - args.push_back(nodes.c_str()); - // args.push_back("-w"); - // args.push_back(walltime.c_str()); - args.push_back("--srun"); - args.push_back("start"); - args.push_back(NULL); - std::vector env; - env.push_back(NULL); - - execvpe("gkfs", const_cast(args.data()), - const_cast(env.data())); - LOGGER_INFO( - "ADM_deploy_adhoc_storage() script didn't execute"); - exit(EXIT_FAILURE); - break; - } - case -1: { - ec = scord::error_code::other; - LOGGER_ERROR("rpc id: {} name: {} to: {} <= " - "body: {{retval: {}}}", - rpc_id, std::quoted(rpc_name), - std::quoted(get_address(req)), ec); - break; - } - default: { - int wstatus = 0; - pid_t retwait = waitpid(pid, &wstatus, 0); - if(retwait == -1) { - LOGGER_ERROR( - "rpc id: {} error_msg: \"Error waitpid code: {}\"", - rpc_id, retwait); - ec = scord::error_code::other; - } else { - if(WEXITSTATUS(wstatus) != 0) { - ec = scord::error_code::other; - } else { - ec = scord::error_code::success; - } - } - break; - } - } - } - - } else { - ec = am_result.error(); - LOGGER_ERROR("rpc id: {} name: {} to: {} <= " - "body: {{retval: {}}}", - rpc_id, std::quoted(rpc_name), - std::quoted(get_address(req)), ec); - } - - const auto resp = generic_response{rpc_id, ec}; - - LOGGER_INFO("rpc id: {} name: {} to: {} <= " - "body: {{retval: {}}}", - rpc_id, std::quoted(rpc_name), std::quoted(get_address(req)), - ec); - - req.respond(resp); -} - -void -tear_down_adhoc_storage(const request& req, std::uint64_t adhoc_id) { - - using scord::network::generic_response; - using scord::network::get_address; - - const auto rpc_name = "ADM_"s + __FUNCTION__; - const auto rpc_id = remote_procedure::new_id(); - - LOGGER_INFO("rpc id: {} name: {} from: {} => " - "body: {{adhoc_id: {}}}", - rpc_id, std::quoted(rpc_name), std::quoted(get_address(req)), - adhoc_id); - - // TODO: actually tear down the adhoc storage instance - - const auto resp = generic_response{rpc_id, scord::error_code::success}; - - LOGGER_INFO("rpc id: {} name: {} to: {} <= " - "body: {{retval: {}}}", - rpc_id, std::quoted(rpc_name), std::quoted(get_address(req)), - scord::error_code::success); - - req.respond(resp); -} - -void -register_pfs_storage(const request& req, const std::string& name, - enum scord::pfs_storage::type type, - const scord::pfs_storage::ctx& ctx) { - - using scord::network::get_address; - - const auto rpc_name = "ADM_"s + __FUNCTION__; - const auto rpc_id = remote_procedure::new_id(); - - LOGGER_INFO("rpc id: {} name: {} from: {} => " - "body: {{name: {}, type: {}, pfs_ctx: {}}}", - rpc_id, std::quoted(rpc_name), std::quoted(get_address(req)), - name, type, ctx); - - scord::error_code ec; - std::optional pfs_id = 0; - auto& pfs_manager = scord::pfs_storage_manager::instance(); - - if(const auto pm_result = pfs_manager.create(type, name, ctx); - pm_result.has_value()) { - const auto& adhoc_storage_info = pm_result.value(); - pfs_id = adhoc_storage_info->pfs_storage().id(); - } else { - LOGGER_ERROR("rpc id: {} error_msg: \"Error creating pfs_storage: {}\"", - rpc_id, pm_result.error()); - ec = pm_result.error(); - } - - const auto resp = response_with_id{rpc_id, ec, pfs_id}; - - LOGGER_INFO("rpc id: {} name: {} to: {} => " - "body: {{retval: {}, pfs_id: {}}}", - rpc_id, std::quoted(rpc_name), std::quoted(get_address(req)), - ec, pfs_id); - - req.respond(resp); -} - -void -update_pfs_storage(const request& req, std::uint64_t pfs_id, - const scord::pfs_storage::ctx& new_ctx) { - - using scord::network::get_address; - - const auto rpc_name = "ADM_"s + __FUNCTION__; - const auto rpc_id = remote_procedure::new_id(); - - LOGGER_INFO("rpc id: {} name: {} from: {} => " - "body: {{pfs_id: {}, new_ctx: {}}}", - rpc_id, std::quoted(rpc_name), std::quoted(get_address(req)), - pfs_id, new_ctx); - - auto& pfs_manager = scord::pfs_storage_manager::instance(); - const auto ec = pfs_manager.update(pfs_id, new_ctx); - - if(!ec) { - LOGGER_ERROR("rpc id: {} error_msg: \"Error updating pfs_storage: {}\"", - rpc_id, ec); - } - - const auto resp = generic_response{rpc_id, ec}; - - LOGGER_INFO("rpc id: {} name: {} to: {} => " - "body: {{retval: {}}}", - rpc_id, std::quoted(rpc_name), std::quoted(get_address(req)), - ec); - - req.respond(resp); -} - -void -remove_pfs_storage(const request& req, std::uint64_t pfs_id) { - - using scord::network::get_address; - - const auto rpc_name = "ADM_"s + __FUNCTION__; - const auto rpc_id = remote_procedure::new_id(); - - LOGGER_INFO("rpc id: {} name: {} from: {} => " - "body: {{pfs_id: {}}}", - rpc_id, std::quoted(rpc_name), std::quoted(get_address(req)), - pfs_id); - - auto& pfs_manager = scord::pfs_storage_manager::instance(); - scord::error_code ec = pfs_manager.remove(pfs_id); - - if(!ec) { - LOGGER_ERROR("rpc id: {} error_msg: \"Error removing pfs storage: {}\"", - rpc_id, pfs_id); - } - - const auto resp = generic_response{rpc_id, ec}; - - LOGGER_INFO("rpc id: {} name: {} to: {} <= " - "body: {{retval: {}}}", - rpc_id, std::quoted(rpc_name), std::quoted(get_address(req)), - ec); - - req.respond(resp); -} - -void -transfer_datasets(const request& req, scord::job_id job_id, - const std::vector& sources, - const std::vector& targets, - const std::vector& limits, - enum scord::transfer::mapping mapping) { - - using scord::network::get_address; - - const auto rpc_name = "ADM_"s + __FUNCTION__; - const auto rpc_id = remote_procedure::new_id(); - - LOGGER_INFO( - "rpc id: {} name: {} from: {} => " - "body: {{job_id: {}, sources: {}, targets: {}, limits: {}, mapping: {}}}", - rpc_id, std::quoted(rpc_name), std::quoted(get_address(req)), - job_id, sources, targets, limits, mapping); - - scord::error_code ec; - - std::optional tx_id; - - // TODO: generate a global ID for the transfer and contact Cargo to - // actually request it - tx_id = 42; - - const auto resp = response_with_id{rpc_id, ec, tx_id}; - - LOGGER_INFO("rpc id: {} name: {} to: {} <= " - "body: {{retval: {}, tx_id: {}}}", - rpc_id, std::quoted(rpc_name), std::quoted(get_address(req)), - ec, tx_id); - - req.respond(resp); -} - -} // namespace scord::network::handlers diff --git a/src/scord/rpc_handlers.hpp b/src/scord/rpc_handlers.hpp deleted file mode 100644 index 1ccc493dcfd43be900b74a4f70e13fed7b41509d..0000000000000000000000000000000000000000 --- a/src/scord/rpc_handlers.hpp +++ /dev/null @@ -1,89 +0,0 @@ -/****************************************************************************** - * Copyright 2021, 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 scord. - * - * scord 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. - * - * scord 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 scord. If not, see . - * - * SPDX-License-Identifier: GPL-3.0-or-later - *****************************************************************************/ - -#ifndef SCORD_RPC_HANDLERS_HPP -#define SCORD_RPC_HANDLERS_HPP - -#include -#include -#include - -namespace scord::network::handlers { - -void -ping(const scord::network::request& req); - -void -register_job(const scord::network::request& req, - const scord::job::resources& job_resources, - const scord::job::requirements& job_requirements, - scord::slurm_job_id slurm_id); - -void -update_job(const request& req, scord::job_id job_id, - const scord::job::resources& new_resources); - -void -remove_job(const request& req, scord::job_id job_id); - -void -register_adhoc_storage(const request& req, const std::string& name, - enum scord::adhoc_storage::type type, - const scord::adhoc_storage::ctx& ctx, - const scord::adhoc_storage::resources& resources); -void -update_adhoc_storage(const request& req, std::uint64_t adhoc_id, - const scord::adhoc_storage::resources& new_resources); - -void -remove_adhoc_storage(const request& req, std::uint64_t adhoc_id); - -void -deploy_adhoc_storage(const request& req, std::uint64_t adhoc_id); - -void -tear_down_adhoc_storage(const request& req, std::uint64_t adhoc_id); - -void -register_pfs_storage(const request& req, const std::string& name, - enum scord::pfs_storage::type type, - const scord::pfs_storage::ctx& ctx); - -void -update_pfs_storage(const request& req, std::uint64_t pfs_id, - const scord::pfs_storage::ctx& new_ctx); - -void -remove_pfs_storage(const request& req, std::uint64_t pfs_id); - -void -transfer_datasets(const request& req, scord::job_id job_id, - const std::vector& sources, - const std::vector& targets, - const std::vector& limits, - enum scord::transfer::mapping mapping); - -} // namespace scord::network::handlers - -#endif // SCORD_RPC_HANDLERS_HPP diff --git a/src/scord/rpc_server.cpp b/src/scord/rpc_server.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fd63ea0104d30b41c56799e1ffe2d0faf018ecc7 --- /dev/null +++ b/src/scord/rpc_server.cpp @@ -0,0 +1,494 @@ +/****************************************************************************** + * Copyright 2021-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 scord. + * + * scord 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. + * + * scord 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 scord. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include "rpc_server.hpp" + +using namespace std::literals; + +namespace scord { + +rpc_server::rpc_server(std::string name, std::string address, bool daemonize, + std::filesystem::path rundir) + : server::server(std::move(name), std::move(address), std::move(daemonize), + std::move(rundir)), + provider::provider(m_network_engine, 0) { + +#define EXPAND(rpc_name) "ADM_" #rpc_name##s, &rpc_server::rpc_name + + provider::define(EXPAND(ping)); + provider::define(EXPAND(register_job)); + provider::define(EXPAND(update_job)); + provider::define(EXPAND(remove_job)); + provider::define(EXPAND(register_adhoc_storage)); + provider::define(EXPAND(update_adhoc_storage)); + provider::define(EXPAND(remove_adhoc_storage)); + provider::define(EXPAND(deploy_adhoc_storage)); + provider::define(EXPAND(tear_down_adhoc_storage)); + provider::define(EXPAND(register_pfs_storage)); + provider::define(EXPAND(update_pfs_storage)); + provider::define(EXPAND(remove_pfs_storage)); + provider::define(EXPAND(transfer_datasets)); + +#undef EXPAND +} + +#define RPC_NAME() ("ADM_"s + __FUNCTION__) + +void +rpc_server::ping(const network::request& req) { + + using network::generic_response; + using network::get_address; + using network::rpc_info; + + const auto rpc = rpc_info::create(RPC_NAME(), get_address(req)); + + LOGGER_INFO("rpc {:>} body: {{}}", rpc); + + const auto resp = generic_response{rpc.id(), scord::error_code::success}; + + LOGGER_INFO("rpc {:<} body: {{retval: {}}}", rpc, + scord::error_code::success); + + req.respond(resp); +} + +void +rpc_server::register_job(const network::request& req, + const scord::job::resources& job_resources, + const scord::job::requirements& job_requirements, + scord::slurm_job_id slurm_id) { + + using network::get_address; + using network::response_with_id; + using network::rpc_info; + + const auto rpc = rpc_info::create(RPC_NAME(), get_address(req)); + + LOGGER_INFO("rpc {:>} body: {{job_resources: {}, job_requirements: {}, " + "slurm_id: {}}}", + rpc, job_resources, job_requirements, slurm_id); + + scord::error_code ec; + std::optional job_id; + + if(const auto jm_result = + m_job_manager.create(slurm_id, job_resources, job_requirements); + jm_result.has_value()) { + + const auto& job_info = jm_result.value(); + + // if the job requires an adhoc storage instance, inform the appropriate + // adhoc_storage instance (if registered) + if(job_requirements.adhoc_storage()) { + const auto adhoc_id = job_requirements.adhoc_storage()->id(); + ec = m_adhoc_manager.add_client_info(adhoc_id, job_info); + + if(!ec) { + goto respond; + } + } + + job_id = job_info->job().id(); + } else { + LOGGER_ERROR("rpc id: {} error_msg: \"Error creating job: {}\"", + rpc.id(), jm_result.error()); + ec = jm_result.error(); + } + +respond: + const auto resp = response_with_id{rpc.id(), ec, job_id}; + + LOGGER_INFO("rpc {:<} body: {{retval: {}, job_id: {}}}", rpc, ec, job_id); + + req.respond(resp); +} + +void +rpc_server::update_job(const network::request& req, scord::job_id job_id, + const scord::job::resources& new_resources) { + + using network::generic_response; + using network::get_address; + using network::rpc_info; + + const auto rpc = rpc_info::create(RPC_NAME(), get_address(req)); + + LOGGER_INFO("rpc {:>} body: {{job_id: {}, new_resources: {}}}", rpc, job_id, + new_resources); + + const auto ec = m_job_manager.update(job_id, new_resources); + + if(!ec) { + LOGGER_ERROR("rpc id: {} error_msg: \"Error updating job: {}\"", + rpc.id(), ec); + } + + const auto resp = generic_response{rpc.id(), ec}; + + LOGGER_INFO("rpc {:<} body: {{retval: {}}}", rpc, ec); + + req.respond(resp); +} + +void +rpc_server::remove_job(const network::request& req, scord::job_id job_id) { + + using network::generic_response; + using network::get_address; + using network::rpc_info; + + const auto rpc = rpc_info::create(RPC_NAME(), get_address(req)); + + LOGGER_INFO("rpc {:>} body: {{job_id: {}}}", rpc, job_id); + + scord::error_code ec; + const auto jm_result = m_job_manager.remove(job_id); + + if(jm_result) { + // if the job was using an adhoc storage instance, inform the + // appropriate adhoc_storage that the job is no longer its client + const auto& job_info = jm_result.value(); + + if(const auto adhoc_storage = job_info->requirements()->adhoc_storage(); + adhoc_storage.has_value()) { + ec = m_adhoc_manager.remove_client_info(adhoc_storage->id()); + } + } else { + LOGGER_ERROR("rpc id: {} error_msg: \"Error removing job: {}\"", + rpc.id(), job_id); + ec = jm_result.error(); + } + + const auto resp = generic_response{rpc.id(), ec}; + + LOGGER_INFO("rpc {:<} body: {{retval: {}}}", rpc, ec); + + req.respond(resp); +} + +void +rpc_server::register_adhoc_storage( + const network::request& req, const std::string& name, + enum scord::adhoc_storage::type type, + const scord::adhoc_storage::ctx& ctx, + const scord::adhoc_storage::resources& resources) { + + using network::get_address; + using network::response_with_id; + using network::rpc_info; + + const auto rpc = rpc_info::create(RPC_NAME(), get_address(req)); + + LOGGER_INFO("rpc {:>} body: {{name: {}, type: {}, adhoc_ctx: {}, " + "adhoc_resources: {}}}", + rpc, name, type, ctx, resources); + + scord::error_code ec; + std::optional adhoc_id; + + if(const auto am_result = + m_adhoc_manager.create(type, name, ctx, resources); + am_result.has_value()) { + const auto& adhoc_storage_info = am_result.value(); + adhoc_id = adhoc_storage_info->adhoc_storage().id(); + } else { + LOGGER_ERROR("rpc id: {} error_msg: \"Error creating adhoc_storage: " + "{}\"", + rpc.id(), am_result.error()); + ec = am_result.error(); + } + + const auto resp = response_with_id{rpc.id(), ec, adhoc_id}; + + LOGGER_INFO("rpc {:<} body: {{retval: {}, adhoc_id: {}}}", rpc, ec, + adhoc_id); + + req.respond(resp); +} + +void +rpc_server::update_adhoc_storage( + const network::request& req, std::uint64_t adhoc_id, + const scord::adhoc_storage::resources& new_resources) { + + using network::generic_response; + using network::get_address; + using network::rpc_info; + + const auto rpc = rpc_info::create(RPC_NAME(), get_address(req)); + + LOGGER_INFO("rpc {:>} body: {{adhoc_id: {}, new_resources: {}}}", rpc, + adhoc_id, new_resources); + + const auto ec = m_adhoc_manager.update(adhoc_id, new_resources); + + if(!ec) { + LOGGER_ERROR( + "rpc id: {} error_msg: \"Error updating adhoc_storage: {}\"", + rpc.id(), ec); + } + + const auto resp = generic_response{rpc.id(), ec}; + + LOGGER_INFO("rpc {:<} body: {{retval: {}}}", rpc, ec); + + req.respond(resp); +} + +void +rpc_server::remove_adhoc_storage(const network::request& req, + std::uint64_t adhoc_id) { + + using network::generic_response; + using network::get_address; + using network::rpc_info; + + const auto rpc = rpc_info::create(RPC_NAME(), get_address(req)); + + LOGGER_INFO("rpc {:>} body: {{adhoc_id: {}}}", rpc, adhoc_id); + + scord::error_code ec = m_adhoc_manager.remove(adhoc_id); + + if(!ec) { + LOGGER_ERROR("rpc id: {} error_msg: \"Error removing job: {}\"", + rpc.id(), adhoc_id); + } + + const auto resp = generic_response{rpc.id(), ec}; + + LOGGER_INFO("rpc {:<} body: {{retval: {}}}", rpc, ec); + + req.respond(resp); +} + +void +rpc_server::deploy_adhoc_storage(const network::request& req, + std::uint64_t adhoc_id) { + + using network::generic_response; + using network::get_address; + using network::rpc_info; + + const auto rpc = rpc_info::create(RPC_NAME(), get_address(req)); + + LOGGER_INFO("rpc {:>} body: {{adhoc_id: {}}}", rpc, adhoc_id); + + auto ec = scord::error_code::success; + + // contact the adhoc controller and ask it to deploy the adhoc storage + if(const auto am_result = m_adhoc_manager.find(adhoc_id); + am_result.has_value()) { + const auto& adhoc_info = am_result.value(); + const auto adhoc_storage = adhoc_info->adhoc_storage(); + + if(const auto lookup_rv = + lookup(adhoc_storage.context().controller_address()); + lookup_rv.has_value()) { + const auto& endp = lookup_rv.value(); + + const auto child_rpc = + rpc.add_child(adhoc_storage.context().controller_address()); + + LOGGER_INFO("rpc {:<} body: {{type: {}, ctx: {}, resources: {}}}", + child_rpc, adhoc_storage.type(), + adhoc_storage.context(), adhoc_storage.get_resources()); + + if(const auto call_rv = endp.call(rpc.name(), adhoc_storage.type(), + adhoc_storage.context(), + adhoc_storage.get_resources()); + call_rv.has_value()) { + + const network::generic_response resp{call_rv.value()}; + ec = resp.error_code(); + + LOGGER_EVAL(resp.error_code(), INFO, ERROR, + "rpc {:>} body: {{retval: {}}} [op_id: {}]", + child_rpc, ec, resp.op_id()); + } else { + ec = error_code::snafu; + LOGGER_ERROR("rpc call failed"); + } + } + } else { + ec = am_result.error(); + LOGGER_ERROR("rpc {:<} body: {{retval: {}}}", rpc, ec); + } + + const auto resp = generic_response{rpc.id(), ec}; + + LOGGER_INFO("rpc {:<} body: {{retval: {}}}", rpc, ec); + + req.respond(resp); +} + +void +rpc_server::tear_down_adhoc_storage(const network::request& req, + std::uint64_t adhoc_id) { + + using network::generic_response; + using network::get_address; + using network::rpc_info; + + const auto rpc = rpc_info::create(RPC_NAME(), get_address(req)); + + LOGGER_INFO("rpc {:>} body: {{adhoc_id: {}}}", rpc, adhoc_id); + + // TODO: actually tear down the adhoc storage instance + + const auto resp = generic_response{rpc.id(), scord::error_code::success}; + + LOGGER_INFO("rpc {:<} body: {{retval: {}}}", rpc, + scord::error_code::success); + + req.respond(resp); +} + +void +rpc_server::register_pfs_storage(const network::request& req, + const std::string& name, + enum scord::pfs_storage::type type, + const scord::pfs_storage::ctx& ctx) { + + using network::get_address; + using network::response_with_id; + using network::rpc_info; + + const auto rpc = rpc_info::create(RPC_NAME(), get_address(req)); + + LOGGER_INFO("rpc {:>} body: {{name: {}, type: {}, pfs_ctx: {}}}", rpc, name, + type, ctx); + + scord::error_code ec; + std::optional pfs_id = 0; + + if(const auto pm_result = m_pfs_manager.create(type, name, ctx); + pm_result.has_value()) { + const auto& adhoc_storage_info = pm_result.value(); + pfs_id = adhoc_storage_info->pfs_storage().id(); + } else { + LOGGER_ERROR("rpc id: {} error_msg: \"Error creating pfs_storage: {}\"", + rpc.id(), pm_result.error()); + ec = pm_result.error(); + } + + const auto resp = response_with_id{rpc.id(), ec, pfs_id}; + + LOGGER_INFO("rpc {:<} body: {{retval: {}, pfs_id: {}}}", rpc, ec, pfs_id); + + req.respond(resp); +} + +void +rpc_server::update_pfs_storage(const network::request& req, + std::uint64_t pfs_id, + const scord::pfs_storage::ctx& new_ctx) { + + using network::generic_response; + using network::get_address; + using network::rpc_info; + + const auto rpc = rpc_info::create(RPC_NAME(), get_address(req)); + + LOGGER_INFO("rpc {:>} body: {{pfs_id: {}, new_ctx: {}}}", rpc, pfs_id, + new_ctx); + + const auto ec = m_pfs_manager.update(pfs_id, new_ctx); + + if(!ec) { + LOGGER_ERROR("rpc id: {} error_msg: \"Error updating pfs_storage: {}\"", + rpc.id(), ec); + } + + const auto resp = generic_response{rpc.id(), ec}; + + LOGGER_INFO("rpc {:<} body: {{retval: {}}}", rpc, ec); + + req.respond(resp); +} + +void +rpc_server::remove_pfs_storage(const network::request& req, + std::uint64_t pfs_id) { + + using network::generic_response; + using network::get_address; + using network::rpc_info; + + const auto rpc = rpc_info::create(RPC_NAME(), get_address(req)); + + LOGGER_INFO("rpc {:>} body: {{pfs_id: {}}}", rpc, pfs_id); + + scord::error_code ec = m_pfs_manager.remove(pfs_id); + + if(!ec) { + LOGGER_ERROR("rpc id: {} error_msg: \"Error removing pfs storage: {}\"", + rpc.id(), pfs_id); + } + + const auto resp = generic_response{rpc.id(), ec}; + + LOGGER_INFO("rpc {:<} body: {{retval: {}}}", rpc, ec); + + req.respond(resp); +} + +void +rpc_server::transfer_datasets(const network::request& req, scord::job_id job_id, + const std::vector& sources, + const std::vector& targets, + const std::vector& limits, + enum scord::transfer::mapping mapping) { + + using network::get_address; + using network::response_with_id; + using network::rpc_info; + + const auto rpc = rpc_info::create(RPC_NAME(), get_address(req)); + + LOGGER_INFO("rpc {:>} body: {{job_id: {}, sources: {}, targets: {}, " + "limits: {}, mapping: {}}}", + rpc, job_id, sources, targets, limits, mapping); + + scord::error_code ec; + + std::optional tx_id; + + // TODO: generate a global ID for the transfer and contact Cargo to + // actually request it + tx_id = 42; + + const auto resp = response_with_id{rpc.id(), ec, tx_id}; + + LOGGER_INFO("rpc {:<} body: {{retval: {}, tx_id: {}}}", rpc, ec, tx_id); + + req.respond(resp); +} + +} // namespace scord diff --git a/src/scord/rpc_server.hpp b/src/scord/rpc_server.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5a0df6f921f3e734ab83e08aff8ca37ff57ab055 --- /dev/null +++ b/src/scord/rpc_server.hpp @@ -0,0 +1,106 @@ +/****************************************************************************** + * Copyright 2021-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 scord. + * + * scord 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. + * + * scord 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 scord. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + *****************************************************************************/ + +#ifndef SCORD_RPC_SERVER_HPP +#define SCORD_RPC_SERVER_HPP + +#include +#include +#include +#include "job_manager.hpp" +#include "adhoc_storage_manager.hpp" +#include "pfs_storage_manager.hpp" + +namespace scord { + +class rpc_server : public network::server, + public network::provider { + +public: + rpc_server(std::string name, std::string address, bool daemonize, + std::filesystem::path rundir); + +private: + void + ping(const network::request& req); + + void + register_job(const network::request& req, + const scord::job::resources& job_resources, + const scord::job::requirements& job_requirements, + scord::slurm_job_id slurm_id); + + void + update_job(const network::request& req, scord::job_id job_id, + const scord::job::resources& new_resources); + + void + remove_job(const network::request& req, scord::job_id job_id); + + void + register_adhoc_storage(const network::request& req, const std::string& name, + enum scord::adhoc_storage::type type, + const scord::adhoc_storage::ctx& ctx, + const scord::adhoc_storage::resources& resources); + void + update_adhoc_storage(const network::request& req, std::uint64_t adhoc_id, + const scord::adhoc_storage::resources& new_resources); + + void + remove_adhoc_storage(const network::request& req, std::uint64_t adhoc_id); + + void + deploy_adhoc_storage(const network::request& req, std::uint64_t adhoc_id); + + void + tear_down_adhoc_storage(const network::request& req, + std::uint64_t adhoc_id); + + void + register_pfs_storage(const network::request& req, const std::string& name, + enum scord::pfs_storage::type type, + const scord::pfs_storage::ctx& ctx); + + void + update_pfs_storage(const network::request& req, std::uint64_t pfs_id, + const scord::pfs_storage::ctx& new_ctx); + + void + remove_pfs_storage(const network::request& req, std::uint64_t pfs_id); + + void + transfer_datasets(const network::request& req, scord::job_id job_id, + const std::vector& sources, + const std::vector& targets, + const std::vector& limits, + enum scord::transfer::mapping mapping); + + job_manager m_job_manager; + adhoc_storage_manager m_adhoc_manager; + pfs_storage_manager m_pfs_manager; +}; + +} // namespace scord + +#endif // SCORD_RPC_SERVER_HPP diff --git a/src/scord/scord.cpp b/src/scord/scord.cpp index a11a93c8820ef3267b8fd887403801207c6ea628..5d87e3e5fce8abe06eeea62d3026cfec41119a86 100644 --- a/src/scord/scord.cpp +++ b/src/scord/scord.cpp @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright 2021, Barcelona Supercomputing Center (BSC), Spain + * Copyright 2021-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). @@ -31,8 +31,7 @@ #include #include -#include -#include "rpc_handlers.hpp" +#include "rpc_server.hpp" #include "defaults.hpp" #include @@ -108,13 +107,12 @@ public: } }; - int main(int argc, char* argv[]) { struct { bool foreground = !scord::config::defaults::daemonize; - scord::logger_type log_type = scord::logger_type::console_color; + logger::logger_type log_type = logger::logger_type::console_color; std::optional output_file; std::optional rundir; std::optional address; @@ -129,7 +127,7 @@ main(int argc, char* argv[]) { app.add_flag_callback( "-C,--force-console", [&]() { - cli_args.log_type = scord::logger_type::console_color; + cli_args.log_type = logger::logger_type::console_color; cli_args.output_file = std::nullopt; }, "Override any logging options defined in the configuration file " @@ -146,7 +144,7 @@ main(int argc, char* argv[]) { app.add_option_function( "-o,--output", [&](const std::string& val) { - cli_args.log_type = scord::logger_type::file; + cli_args.log_type = logger::logger_type::file; cli_args.output_file = fs::path{val}; }, "Write any output to FILENAME console") @@ -168,7 +166,7 @@ main(int argc, char* argv[]) { ->group(""); global_settings->add_option_function( "--logfile", [&](const std::string& val) { - cli_args.log_type = scord::logger_type::file; + cli_args.log_type = logger::logger_type::file; cli_args.output_file = fs::path{val}; }); global_settings->add_option("--rundir", cli_args.rundir); @@ -186,32 +184,9 @@ main(int argc, char* argv[]) { } try { - scord::network::server srv( - progname, *cli_args.address, !cli_args.foreground, - cli_args.rundir.value_or(fs::current_path())); - + scord::rpc_server srv(progname, *cli_args.address, !cli_args.foreground, + cli_args.rundir.value_or(fs::current_path())); srv.configure_logger(cli_args.log_type, cli_args.output_file); - - // convenience macro to ensure the names of an RPC and - // its handler always match -#define EXPAND(rpc_name) "ADM_" #rpc_name##s, scord::network::handlers::rpc_name - - srv.set_handler(EXPAND(ping)); - srv.set_handler(EXPAND(register_job)); - srv.set_handler(EXPAND(update_job)); - srv.set_handler(EXPAND(remove_job)); - srv.set_handler(EXPAND(register_adhoc_storage)); - srv.set_handler(EXPAND(update_adhoc_storage)); - srv.set_handler(EXPAND(remove_adhoc_storage)); - srv.set_handler(EXPAND(deploy_adhoc_storage)); - srv.set_handler(EXPAND(tear_down_adhoc_storage)); - srv.set_handler(EXPAND(register_pfs_storage)); - srv.set_handler(EXPAND(update_pfs_storage)); - srv.set_handler(EXPAND(remove_pfs_storage)); - srv.set_handler(EXPAND(transfer_datasets)); - -#undef EXPAND - return srv.run(); } catch(const std::exception& ex) { fmt::print(stderr,