Loading etc/scord-ctl.conf.in +138 −0 Original line number Diff line number Diff line Loading @@ -35,7 +35,145 @@ config: command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/gekkofs.sh stop --workdir {ADHOC_DIRECTORY} expand: environment: command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/gekkofs.sh expand --hosts {ADHOC_NODES} shrink: environment: command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/gekkofs.sh shrink --hosts {ADHOC_NODES} dataclay: # The default working directory for adhoc instances of this type working_directory: /tmp/dataclay startup: # Specific environment variables that should be set for the adhoc # instance. These will be merged with the environment variables # already set by Slurm. environment: VAR0: value0 VAR1: value1 # The command that `scord-ctl` will use to start an adhoc instance of # this type. The following variables are supported that will be # automatically replaced by scord-ctl if found between curly braces: # * ADHOC_NODES: A comma separated list of valid job hostnames that # can be used to start the adhoc instance. # * ADHOC_DIRECTORY: A unique working directory for each specific # adhoc instance. This directory will be created by scord-ctl under # `working_directory` and automatically removed after the adhoc # instance has been shut down. # * ADHOC_ID: - A unique ID for the adhoc instance. command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/dataclay.sh start --hosts {ADHOC_NODES} --workdir {ADHOC_DIRECTORY} --datadir {ADHOC_DIRECTORY}/data --mountdir {ADHOC_DIRECTORY}/mnt shutdown: environment: command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/dataclay.sh stop --workdir {ADHOC_DIRECTORY} expand: environment: command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/dataclay.sh expand --hosts {ADHOC_NODES} shrink: environment: command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/dataclay.sh shrink --hosts {ADHOC_NODES} expand: # The default working directory for adhoc instances of this type working_directory: /tmp/expand startup: # Specific environment variables that should be set for the adhoc # instance. These will be merged with the environment variables # already set by Slurm. environment: VAR0: value0 VAR1: value1 # The command that `scord-ctl` will use to start an adhoc instance of # this type. The following variables are supported that will be # automatically replaced by scord-ctl if found between curly braces: # * ADHOC_NODES: A comma separated list of valid job hostnames that # can be used to start the adhoc instance. # * ADHOC_DIRECTORY: A unique working directory for each specific # adhoc instance. This directory will be created by scord-ctl under # `working_directory` and automatically removed after the adhoc # instance has been shut down. # * ADHOC_ID: - A unique ID for the adhoc instance. command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/expand.sh start --hosts {ADHOC_NODES} --workdir {ADHOC_DIRECTORY} --datadir {ADHOC_DIRECTORY}/data --mountdir {ADHOC_DIRECTORY}/mnt shutdown: environment: command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/expand.sh stop --workdir {ADHOC_DIRECTORY} expand: environment: command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/expand.sh expand --hosts {ADHOC_NODES} shrink: environment: command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/expand.sh shrink --hosts {ADHOC_NODES} hercules: # The default working directory for adhoc instances of this type working_directory: /tmp/hercules startup: # Specific environment variables that should be set for the adhoc # instance. These will be merged with the environment variables # already set by Slurm. environment: VAR0: value0 VAR1: value1 # The command that `scord-ctl` will use to start an adhoc instance of # this type. The following variables are supported that will be # automatically replaced by scord-ctl if found between curly braces: # * ADHOC_NODES: A comma separated list of valid job hostnames that # can be used to start the adhoc instance. # * ADHOC_DIRECTORY: A unique working directory for each specific # adhoc instance. This directory will be created by scord-ctl under # `working_directory` and automatically removed after the adhoc # instance has been shut down. # * ADHOC_ID: - A unique ID for the adhoc instance. command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/hercules.sh start --hosts {ADHOC_NODES} --workdir {ADHOC_DIRECTORY} --datadir {ADHOC_DIRECTORY}/data --mountdir {ADHOC_DIRECTORY}/mnt shutdown: environment: command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/hercules.sh stop --workdir {ADHOC_DIRECTORY} expand: environment: command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/hercules.sh expand --hosts {ADHOC_NODES} shrink: environment: command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/hercules.sh shrink --hosts {ADHOC_NODES} # default storage tiers made available to applications storage: Loading plugins/adhoc_services.d/gekkofs.sh +1 −1 Original line number Diff line number Diff line #!/usr/bin/env bash echo "GEKKOFS Script Called" exit 0 src/scord-ctl/command.cpp +46 −0 Original line number Diff line number Diff line Loading @@ -135,6 +135,52 @@ command::eval(const std::string& adhoc_id, return command{result, m_env}; } command command::eval(const std::string& adhoc_id, const std::vector<std::string>& adhoc_nodes) const { // generate a regex from a map of key/value pairs constexpr auto regex_from_map = [](const std::map<std::string, std::string>& m) -> std::regex { std::string result; for(const auto& [key, value] : m) { const auto escaped_key = std::regex_replace(key, std::regex{R"([{}])"}, R"(\$&)"); result += fmt::format("{}|", escaped_key); } result.pop_back(); return std::regex{result}; }; const std::map<std::string, std::string> replacements{ {std::string{keywords_malleability.at(0)}, adhoc_id}, {std::string{keywords_malleability.at(1)}, fmt::format("\"{}\"", fmt::join(adhoc_nodes, ","))}}; // make sure that we fail if we ever add a new keyword and forget to add // a replacement for it assert(replacements.size() == keywords_malleability.size()); std::string result; const auto re = regex_from_map(replacements); auto it = std::sregex_iterator(m_cmdline.begin(), m_cmdline.end(), re); auto end = std::sregex_iterator{}; std::string::size_type last_pos = 0; for(; it != end; ++it) { const auto& match = *it; result += m_cmdline.substr(last_pos, match.position() - last_pos); result += replacements.at(match.str()); last_pos = match.position() + match.length(); } result += m_cmdline.substr(last_pos, m_cmdline.length() - last_pos); return command{result, m_env}; } std::vector<std::string> command::as_vector() const { std::vector<std::string> tmp; Loading src/scord-ctl/command.hpp +16 −0 Original line number Diff line number Diff line Loading @@ -109,6 +109,8 @@ public: static constexpr std::array<std::string_view, 3> keywords = { "{ADHOC_ID}", "{ADHOC_DIRECTORY}", "{ADHOC_NODES}"}; static constexpr std::array<std::string_view, 2> keywords_malleability = { "{ADHOC_ID}", "{ADHOC_NODES}"}; /** * @brief Construct a command. * Loading Loading @@ -152,6 +154,20 @@ public: const std::filesystem::path& adhoc_directory, const std::vector<std::string>& adhoc_nodes) const; /** * @brief Return a copy of the current `command` where all the keywords in * its command line template have been replaced with string * representations of the arguments provided. * * @param adhoc_id The ID of the adhoc storage system. * @param adhoc_nodes The nodes where the adhoc storage will run. * @return The evaluated command. */ command eval(const std::string& adhoc_id, const std::vector<std::string>& adhoc_nodes) const; /** * @brief Get the command line to be executed as a vector of strings. The * command line is split on spaces with each string in the resulting Loading src/scord-ctl/config_file.cpp +24 −3 Original line number Diff line number Diff line Loading @@ -195,6 +195,9 @@ parse_adhoc_config_node(const ryml::ConstNodeRef& node) { std::filesystem::path working_directory; std::optional<scord_ctl::command> startup_command; std::optional<scord_ctl::command> shutdown_command; std::optional<scord_ctl::command> expand_command; std::optional<scord_ctl::command> shrink_command; for(const auto& child : node) { Loading @@ -212,6 +215,10 @@ parse_adhoc_config_node(const ryml::ConstNodeRef& node) { startup_command = ::parse_command_node(child); } else if(child.key() == "shutdown") { shutdown_command = ::parse_command_node(child); } else if(child.key() == "expand") { expand_command = ::parse_command_node(child); } else if(child.key() == "shrink") { shrink_command = ::parse_command_node(child); } else { fmt::print(stderr, "WARNING: Unknown key: '{}'. Ignored.\n", child.key()); Loading @@ -222,7 +229,8 @@ parse_adhoc_config_node(const ryml::ConstNodeRef& node) { throw std::runtime_error{"missing required `working_directory` key"}; } return {working_directory, *startup_command, *shutdown_command}; return {working_directory, *startup_command, *shutdown_command, *expand_command, *shrink_command}; } /** Loading Loading @@ -302,10 +310,13 @@ namespace scord_ctl::config { adhoc_storage_config::adhoc_storage_config( std::filesystem::path working_directory, command startup_command, command shutdown_command) command shutdown_command, command expand_command, command shrink_command) : m_working_directory(std::move(working_directory)), m_startup_command(std::move(startup_command)), m_shutdown_command(std::move(shutdown_command)) {} m_shutdown_command(std::move(shutdown_command)), m_expand_command(std::move(expand_command)), m_shrink_command(std::move(shrink_command)) {} const std::filesystem::path& adhoc_storage_config::working_directory() const { Loading @@ -322,6 +333,16 @@ adhoc_storage_config::shutdown_command() const { return m_shutdown_command; } const command& adhoc_storage_config::expand_command() const { return m_expand_command; } const command& adhoc_storage_config::shrink_command() const { return m_shrink_command; } config_file::config_file(const std::filesystem::path& path) { std::ifstream input{path}; Loading Loading
etc/scord-ctl.conf.in +138 −0 Original line number Diff line number Diff line Loading @@ -35,7 +35,145 @@ config: command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/gekkofs.sh stop --workdir {ADHOC_DIRECTORY} expand: environment: command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/gekkofs.sh expand --hosts {ADHOC_NODES} shrink: environment: command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/gekkofs.sh shrink --hosts {ADHOC_NODES} dataclay: # The default working directory for adhoc instances of this type working_directory: /tmp/dataclay startup: # Specific environment variables that should be set for the adhoc # instance. These will be merged with the environment variables # already set by Slurm. environment: VAR0: value0 VAR1: value1 # The command that `scord-ctl` will use to start an adhoc instance of # this type. The following variables are supported that will be # automatically replaced by scord-ctl if found between curly braces: # * ADHOC_NODES: A comma separated list of valid job hostnames that # can be used to start the adhoc instance. # * ADHOC_DIRECTORY: A unique working directory for each specific # adhoc instance. This directory will be created by scord-ctl under # `working_directory` and automatically removed after the adhoc # instance has been shut down. # * ADHOC_ID: - A unique ID for the adhoc instance. command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/dataclay.sh start --hosts {ADHOC_NODES} --workdir {ADHOC_DIRECTORY} --datadir {ADHOC_DIRECTORY}/data --mountdir {ADHOC_DIRECTORY}/mnt shutdown: environment: command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/dataclay.sh stop --workdir {ADHOC_DIRECTORY} expand: environment: command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/dataclay.sh expand --hosts {ADHOC_NODES} shrink: environment: command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/dataclay.sh shrink --hosts {ADHOC_NODES} expand: # The default working directory for adhoc instances of this type working_directory: /tmp/expand startup: # Specific environment variables that should be set for the adhoc # instance. These will be merged with the environment variables # already set by Slurm. environment: VAR0: value0 VAR1: value1 # The command that `scord-ctl` will use to start an adhoc instance of # this type. The following variables are supported that will be # automatically replaced by scord-ctl if found between curly braces: # * ADHOC_NODES: A comma separated list of valid job hostnames that # can be used to start the adhoc instance. # * ADHOC_DIRECTORY: A unique working directory for each specific # adhoc instance. This directory will be created by scord-ctl under # `working_directory` and automatically removed after the adhoc # instance has been shut down. # * ADHOC_ID: - A unique ID for the adhoc instance. command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/expand.sh start --hosts {ADHOC_NODES} --workdir {ADHOC_DIRECTORY} --datadir {ADHOC_DIRECTORY}/data --mountdir {ADHOC_DIRECTORY}/mnt shutdown: environment: command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/expand.sh stop --workdir {ADHOC_DIRECTORY} expand: environment: command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/expand.sh expand --hosts {ADHOC_NODES} shrink: environment: command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/expand.sh shrink --hosts {ADHOC_NODES} hercules: # The default working directory for adhoc instances of this type working_directory: /tmp/hercules startup: # Specific environment variables that should be set for the adhoc # instance. These will be merged with the environment variables # already set by Slurm. environment: VAR0: value0 VAR1: value1 # The command that `scord-ctl` will use to start an adhoc instance of # this type. The following variables are supported that will be # automatically replaced by scord-ctl if found between curly braces: # * ADHOC_NODES: A comma separated list of valid job hostnames that # can be used to start the adhoc instance. # * ADHOC_DIRECTORY: A unique working directory for each specific # adhoc instance. This directory will be created by scord-ctl under # `working_directory` and automatically removed after the adhoc # instance has been shut down. # * ADHOC_ID: - A unique ID for the adhoc instance. command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/hercules.sh start --hosts {ADHOC_NODES} --workdir {ADHOC_DIRECTORY} --datadir {ADHOC_DIRECTORY}/data --mountdir {ADHOC_DIRECTORY}/mnt shutdown: environment: command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/hercules.sh stop --workdir {ADHOC_DIRECTORY} expand: environment: command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/hercules.sh expand --hosts {ADHOC_NODES} shrink: environment: command: @CMAKE_INSTALL_FULL_DATADIR@/@PROJECT_NAME@/adhoc_services.d/hercules.sh shrink --hosts {ADHOC_NODES} # default storage tiers made available to applications storage: Loading
plugins/adhoc_services.d/gekkofs.sh +1 −1 Original line number Diff line number Diff line #!/usr/bin/env bash echo "GEKKOFS Script Called" exit 0
src/scord-ctl/command.cpp +46 −0 Original line number Diff line number Diff line Loading @@ -135,6 +135,52 @@ command::eval(const std::string& adhoc_id, return command{result, m_env}; } command command::eval(const std::string& adhoc_id, const std::vector<std::string>& adhoc_nodes) const { // generate a regex from a map of key/value pairs constexpr auto regex_from_map = [](const std::map<std::string, std::string>& m) -> std::regex { std::string result; for(const auto& [key, value] : m) { const auto escaped_key = std::regex_replace(key, std::regex{R"([{}])"}, R"(\$&)"); result += fmt::format("{}|", escaped_key); } result.pop_back(); return std::regex{result}; }; const std::map<std::string, std::string> replacements{ {std::string{keywords_malleability.at(0)}, adhoc_id}, {std::string{keywords_malleability.at(1)}, fmt::format("\"{}\"", fmt::join(adhoc_nodes, ","))}}; // make sure that we fail if we ever add a new keyword and forget to add // a replacement for it assert(replacements.size() == keywords_malleability.size()); std::string result; const auto re = regex_from_map(replacements); auto it = std::sregex_iterator(m_cmdline.begin(), m_cmdline.end(), re); auto end = std::sregex_iterator{}; std::string::size_type last_pos = 0; for(; it != end; ++it) { const auto& match = *it; result += m_cmdline.substr(last_pos, match.position() - last_pos); result += replacements.at(match.str()); last_pos = match.position() + match.length(); } result += m_cmdline.substr(last_pos, m_cmdline.length() - last_pos); return command{result, m_env}; } std::vector<std::string> command::as_vector() const { std::vector<std::string> tmp; Loading
src/scord-ctl/command.hpp +16 −0 Original line number Diff line number Diff line Loading @@ -109,6 +109,8 @@ public: static constexpr std::array<std::string_view, 3> keywords = { "{ADHOC_ID}", "{ADHOC_DIRECTORY}", "{ADHOC_NODES}"}; static constexpr std::array<std::string_view, 2> keywords_malleability = { "{ADHOC_ID}", "{ADHOC_NODES}"}; /** * @brief Construct a command. * Loading Loading @@ -152,6 +154,20 @@ public: const std::filesystem::path& adhoc_directory, const std::vector<std::string>& adhoc_nodes) const; /** * @brief Return a copy of the current `command` where all the keywords in * its command line template have been replaced with string * representations of the arguments provided. * * @param adhoc_id The ID of the adhoc storage system. * @param adhoc_nodes The nodes where the adhoc storage will run. * @return The evaluated command. */ command eval(const std::string& adhoc_id, const std::vector<std::string>& adhoc_nodes) const; /** * @brief Get the command line to be executed as a vector of strings. The * command line is split on spaces with each string in the resulting Loading
src/scord-ctl/config_file.cpp +24 −3 Original line number Diff line number Diff line Loading @@ -195,6 +195,9 @@ parse_adhoc_config_node(const ryml::ConstNodeRef& node) { std::filesystem::path working_directory; std::optional<scord_ctl::command> startup_command; std::optional<scord_ctl::command> shutdown_command; std::optional<scord_ctl::command> expand_command; std::optional<scord_ctl::command> shrink_command; for(const auto& child : node) { Loading @@ -212,6 +215,10 @@ parse_adhoc_config_node(const ryml::ConstNodeRef& node) { startup_command = ::parse_command_node(child); } else if(child.key() == "shutdown") { shutdown_command = ::parse_command_node(child); } else if(child.key() == "expand") { expand_command = ::parse_command_node(child); } else if(child.key() == "shrink") { shrink_command = ::parse_command_node(child); } else { fmt::print(stderr, "WARNING: Unknown key: '{}'. Ignored.\n", child.key()); Loading @@ -222,7 +229,8 @@ parse_adhoc_config_node(const ryml::ConstNodeRef& node) { throw std::runtime_error{"missing required `working_directory` key"}; } return {working_directory, *startup_command, *shutdown_command}; return {working_directory, *startup_command, *shutdown_command, *expand_command, *shrink_command}; } /** Loading Loading @@ -302,10 +310,13 @@ namespace scord_ctl::config { adhoc_storage_config::adhoc_storage_config( std::filesystem::path working_directory, command startup_command, command shutdown_command) command shutdown_command, command expand_command, command shrink_command) : m_working_directory(std::move(working_directory)), m_startup_command(std::move(startup_command)), m_shutdown_command(std::move(shutdown_command)) {} m_shutdown_command(std::move(shutdown_command)), m_expand_command(std::move(expand_command)), m_shrink_command(std::move(shrink_command)) {} const std::filesystem::path& adhoc_storage_config::working_directory() const { Loading @@ -322,6 +333,16 @@ adhoc_storage_config::shutdown_command() const { return m_shutdown_command; } const command& adhoc_storage_config::expand_command() const { return m_expand_command; } const command& adhoc_storage_config::shrink_command() const { return m_shrink_command; } config_file::config_file(const std::filesystem::path& path) { std::ifstream input{path}; Loading