Crate slurm_spank

source ·
Expand description

Rust bindings for writing Slurm SPANK Plugins

§Introduction

This crate allows to write Slurm SPANK plugins using Rust. To learn more about capabilities available through SPANK please refer to the official SPANK documentation.

To create a SPANK plugin using this crate, you need to define a struct for which you implement the Plugin trait and to make it available as a SPANK plugin using the SPANK_PLUGIN! macro.

The methods of the Plugin trait correspond to the callbacks defined by the SPANK API such as init_post_opt, task_post_fork etc. These methods have a default implementation which means you only need to implement the callbacks relevant for your plugin.

Each callback method is passed a SpankHandle reference which allows to interact with Slurm through the SPANK API.

When returning an Err from a callback an error message will be displayed and/or logged by default, depending on the context. This behaviour may be overridden by the report_error method. A default Subscriber is also configured to facilitate the use of the tracing crate for logging and error reporting while using SPANK log facilities, such as in the example below. This can be overridden by the setup method.

§Example: hello.so

The following example implements a simple hello world plugin. A more complete example is provided in the example directory of the repository which shows how to implement the same renice plugin that is given as an example of the C SPANK API in the Slurm SPANK documentation.

use eyre::WrapErr;
use slurm_spank::{
    spank_log_user, Context, Plugin, SpankHandle, SpankOption, SLURM_VERSION_NUMBER, SPANK_PLUGIN,
};

use std::error::Error;
use tracing::info;

// All spank plugins must define this macro for the
// Slurm plugin loader.
SPANK_PLUGIN!(b"hello", SLURM_VERSION_NUMBER, SpankHello);

#[derive(Default)]
struct SpankHello {
    greet: Option<String>,
}

unsafe impl Plugin for SpankHello {
    fn init(&mut self, spank: &mut SpankHandle) -> Result<(), Box<dyn Error>> {
        // Register the --greet=name option
        match spank.context()? {
            Context::Local | Context::Remote => {
                spank
                    .register_option(
                        SpankOption::new("greet")
                            .takes_value("name")
                            .usage("Greet [name] before running tasks"),
                    )
                    .wrap_err("Failed to register greet option")?;
            }
            _ => {}
        }
        Ok(())
    }
    fn init_post_opt(&mut self, spank: &mut SpankHandle) -> Result<(), Box<dyn Error>> {
        // Check if the option was set
        self.greet = spank
            .get_option_value("greet")
            .wrap_err("Failed to read --greet option")?
            .map(|s| s.to_string());
        if let Some(name) = &self.greet {
            info!("User opted to greet {name}");
        }
        Ok(())
    }

    fn user_init(&mut self, _spank: &mut SpankHandle) -> Result<(), Box<dyn Error>> {
        // Greet as requested
        if let Some(name) = &self.greet {
            spank_log_user!("Hello {name}!");
        }
        Ok(())
    }
}

The following Cargo.toml can be used to build this example plugin

 [package]
 name = "slurm-spank-hello"
 version = "0.1.0"
 edition = "2021"

 [lib]
 crate-type = ["cdylib"]

 [dependencies]
 eyre = "0.6.8"
 slurm-spank = "0.3"
 tracing = "0.1.37"

Macros§

Structs§

  • Handle to the Slurm interface exposed to SPANK plugins. It provides methods to query Slurm from a plugin.
  • SPANK plugin command-line option that can be registered with SpankHandle::register_option

Enums§

  • Context in which a plugin is loaded during a Slurm job
  • Log level for SPANK logging functions
  • Errors returned by the underlying SPANK API
  • Main Error enum for interfaces provided by this crate

Constants§

Traits§

  • Implement this trait to create a SPANK plugin

Functions§