diff --git a/plugins/spank_qrmi/README.md b/plugins/spank_qrmi/README.md index 20c9eb4..c86bb7f 100644 --- a/plugins/spank_qrmi/README.md +++ b/plugins/spank_qrmi/README.md @@ -88,6 +88,17 @@ Note that administrator needs to create `qrmi_config.json` file and specify the optional /usr/lib64/slurm/spank_qrmi.so /etc/slurm/qrmi_config.json ``` +> [!NOTE] +> There are optional argumentis available. It allows you to add environment variables to the Slurm process where the SPANK plugin is loaded. The format for specifying environment variables is defined as follows. +> ```bash +> --env:{variable name}={value} +> ``` +> +> For example, when interacting with Quantum resources via an HTTP proxy, the environment variables `http_proxy`, `https_proxy`, and `no_proxy` are required. These can be added as shown below. +> ```bash +> optional /usr/lib64/slurm/spank_qrmi.so /etc/slurm/qrmi_config.json --env:http_proxy=http://192.168.1.128:3128 --env:https_proxy=http://192.168.1.128:3128 +> ``` + For allocator node, your don't need to specify the path to qrmi_config.json like below. ```bash diff --git a/plugins/spank_qrmi/spank_qrmi.c b/plugins/spank_qrmi/spank_qrmi.c index b6f22f0..c12f60b 100644 --- a/plugins/spank_qrmi/spank_qrmi.c +++ b/plugins/spank_qrmi/spank_qrmi.c @@ -26,6 +26,8 @@ #include "qrmi.h" #include "spank_qrmi.h" +extern char **environ; + /* * Spank plugin for QRMI. */ @@ -54,6 +56,32 @@ static void acquired_resource_destroy(void *object); static qpu_resource_t *_acquire_qpu(spank_t spank_ctxt, char *name, QrmiResourceType type); static void _release_qpu(qpu_resource_t *res); +/* + * @function _dump_environ + * + * Dumps all environment variables set for the current process. + */ +static void _dump_environ() { + char **s = environ; + int pid = (int)getpid(); + int uid = (int)getuid(); + + slurm_debug("%s(%d, %d): environment variables ---", plugin_name, pid, uid); + for (; *s; s++) { + slurm_debug("%s(%d, %d): %s", plugin_name, pid, uid, *s); + } +} + +/* + * @function _starts_with + * + * Tests if this string(`str`) starts with the specified `prefix`. + */ +static bool _starts_with(const char *str, const char *prefix) +{ + return strncmp(prefix, str, strlen(prefix)) == 0; +} + /* * @function _qpu_names_opt_cb * @@ -183,11 +211,37 @@ int slurm_spank_init_post_opt(spank_t spank_ctxt, int argc, char **argv) { QrmiConfig *cnf = qrmi_config_load(argv[0]); if (cnf == NULL) { - slurm_error("%s, No QRMI config file (%s)", plugin_name, argv[0]); + const char* last_error = qrmi_get_last_error(); + slurm_error("%s, Failed to load QRMI config file(%s). %s", + plugin_name, argv[0], last_error); + spank_setenv(spank_ctxt, "QRMI_PLUGIN_ERROR", last_error, KEEP_IF_EXISTS); + qrmi_string_free((char*)last_error); return SLURM_ERROR; } slurm_debug("%s, config: %p", plugin_name, (void *)cnf); + /* + * Parses optional plugin arguments. + * + * Currently, only environment variable settings prefixed with + * --env:{variable name}={value} are supported. + */ + for (int i = 1; i < argc; i++) { + if (_starts_with(argv[i], "--env:")) { + const char *input = &argv[i][strlen("--env:")]; + const char *delimiter = strchr(input, '='); + if (delimiter != NULL) { + size_t key_len = (size_t)(delimiter - input); + char env_name[key_len + 1]; + strncpy(env_name, input, key_len); + env_name[key_len] = '\0'; + const char *env_value = delimiter + 1;; + setenv(env_name, env_value, OVERWRITE); + spank_setenv(spank_ctxt, env_name, env_value, OVERWRITE); + } + } + } + size_t buflen = strlen(g_qpu_names_opt) + 1; char *bufp = (char *)malloc(buflen); char *rest = bufp; @@ -258,6 +312,8 @@ int slurm_spank_init_post_opt(spank_t spank_ctxt, int argc, char **argv) { KEEP_IF_EXISTS); } + _dump_environ(); + /* * Acquire QPU resource. */ @@ -564,6 +620,7 @@ static qpu_resource_t *_acquire_qpu(spank_t spank_ctxt, char *name, QrmiResource if ((rc != QRMI_RETURN_CODE_SUCCESS) || (is_accessible == false)) { last_error = qrmi_get_last_error(); slurm_error("%s, %s is not accessible. %s", plugin_name, name, last_error); + spank_setenv(spank_ctxt, "QRMI_PLUGIN_ERROR", last_error, KEEP_IF_EXISTS); qrmi_string_free((char*)last_error); qrmi_resource_free(qrmi); return NULL;