Commit 70725356 authored by Frank Winkler's avatar Frank Winkler
Browse files

Test implementation for PrEp-Plugin.

parent d3b465e0
# Build and Install
- Adjust `build.make` to your needs
- Run `make -f build.make install`
# Config
Update slurm.conf with the plugin (comma seperated list):
```conf
PrEpPlugins=pika
```
SLURM_ROOT_DIR = /usr
SLURM_INC_DIR = $(SLURM_ROOT_DIR)/include
SLURM_LIB_DIR = /usr/lib64/slurm
SLURM_BUILD = 20.02.7
SLURM_BUILD_DIR = /root/rpmbuild/BUILD/slurm-$(SLURM_BUILD)
PLUGIN_TYPE = prep
PLUGIN_NAME = pika
PLUGIN_FILE = $(PLUGIN_TYPE)_$(PLUGIN_NAME).so
SRC_FILE = slurm-prep-pika.c
CC = gcc
CFLAGS ?= -Wall -fPIC -g -I$(SLURM_INC_DIR) -I$(SLURM_BUILD_DIR)
LDFLAGS ?= --shared -L.
all: $(PLUGIN_FILE)
default: $(PLUGIN_FILE)
$(PLUGIN_FILE): $(SRC_FILE)
$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@
install: $(PLUGIN_FILE)
install -m 755 $(PLUGIN_FILE) $(SLURM_LIB_DIR)
clean:
rm -f $(PLUGIN_FILE)
mrproper: clean
/*****************************************************************************\
* prep_script.c - PrEp script plugin, handles Prolog / Epilog /
* PrologSlurmctld / EpilogSlurmctld scripts
*****************************************************************************
* Written by Frank Winkler
*
* LICENSE NOTICE ?!?!?!?!
\*****************************************************************************/
#include "slurm/slurm.h"
#include "slurm/slurm_errno.h"
#include "src/common/prep.h"
#include "src/common/macros.h"
#include "src/common/xmalloc.h"
#include "src/common/xstring.h"
#include "src/common/parse_time.h"
/*
* These variables are required by the generic plugin interface. If they
* are not found in the plugin, the plugin loader will ignore it.
*
* plugin_name - a string giving a human-readable description of the
* plugin. There is no maximum length, but the symbol must refer to
* a valid string.
*
* plugin_type - a string suggesting t#include <time.h>he type of the plugin or its
* applicability to a particular form of data or method of data handling.
* If the low-level plugin API is used, the contents of this string are
* unimportant and may be anything. Slurm uses the higher-level plugin
* interface which requires this string to be of the form
*
* <application>/<method>
*
* where <application> is a description of the intended application of
* the plugin (e.g., "auth" for Slurm authentication) and <method> is a
* description of how this plugin satisfies that application. Slurm will
* only load authentication plugins if the plugin_type string has a prefix
* of "auth/".
*
* plugin_version - an unsigned 32-bit integer containing the Slurm version
* (major.minor.micro combined into a single number).
*/
#define PLUGIN_NAME "PrEp-pika: "
#define STRING_LEN 256
const char plugin_name[] = "PrEp plugin pika";
const char plugin_type[] = "prep/pika";
const uint32_t plugin_version = SLURM_VERSION_NUMBER;
static bool have_prolog_slurmctld = false;
static bool have_epilog_slurmctld = false;
void (*prolog_slurmctld_callback)(int rc, uint32_t job_id) = NULL;
void (*epilog_slurmctld_callback)(int rc, uint32_t job_id) = NULL;
static pthread_mutex_t plugin_log_lock = PTHREAD_MUTEX_INITIALIZER;
/* Added spank_like output functions for convenience */
extern void slurm_info (const char *format, ...)
__attribute__ ((format (printf, 1, 2)));
extern void slurm_error (const char *format, ...)
__attribute__ ((format (printf, 1, 2)));
extern void slurm_verbose (const char *format, ...)
__attribute__ ((format (printf, 1, 2)));
extern void slurm_debug (const char *format, ...)
__attribute__ ((format (printf, 1, 2)));
extern void slurm_debug2 (const char *format, ...)
__attribute__ ((format (printf, 1, 2)));
extern void slurm_debug3 (const char *format, ...)
__attribute__ ((format (printf, 1, 2)));
/* Forward declarations */
static int pika_log(int job_id, char *job_data, bool is_epilog);
static void job_state(job_record_t *job_ptr, char **state);
static void job_data_prolog(job_record_t *job_ptr, char **job_data);
static void job_data_epilog(job_record_t *job_ptr, char **job_data);
extern int init(void)
{
slurm_info(PLUGIN_NAME "init\n");
//gpu_plugin_init();
return SLURM_SUCCESS;
}
extern void fini(void)
{
slurm_info(PLUGIN_NAME "fini\n");
//gpu_plugin_fini();
}
extern void prep_p_register_callbacks(prep_callbacks_t *callbacks)
{
slurm_info(PLUGIN_NAME "prep_p_register_callbacks\n");
/*
* Cannot safely run these without a valid callback, so disable
* them.
*/
if (!(prolog_slurmctld_callback = callbacks->prolog_slurmctld))
have_prolog_slurmctld = false;
if (!(epilog_slurmctld_callback = callbacks->epilog_slurmctld))
have_epilog_slurmctld = false;
}
extern int prep_p_prolog(job_env_t *job_env, slurm_cred_t *cred)
{
slurm_info(PLUGIN_NAME "prep_p_prolog\n");
return SLURM_SUCCESS;
}
extern int prep_p_epilog(job_env_t *job_env, slurm_cred_t *cred)
{
slurm_info(PLUGIN_NAME "prep_p_epilog\n");
return SLURM_SUCCESS;
}
extern int prep_p_prolog_slurmctld(job_record_t *job_ptr, bool *async)
{
int rc = SLURM_SUCCESS;
/* use user id */
// if ( strcmp(job_ptr->user_name, "fwinkler") != 0 &&
// strcmp(job_ptr->user_name, "rotscher") != 0 )
// return rc;
slurm_info(PLUGIN_NAME "prep_p_prolog_slurmctld\n");
char *job_data = xmalloc(sizeof(char) * STRING_LEN);
job_data_prolog(job_ptr, &job_data);
*async = have_prolog_slurmctld;
if (*async) {
/* MUST run before async task finishes */
prolog_slurmctld_callback(rc, job_ptr->job_id);
}
// Some async task
if (rc == SLURM_SUCCESS) {
pika_log(job_ptr->job_id, job_data, false);
}
return rc;
}
extern int prep_p_epilog_slurmctld(job_record_t *job_ptr, bool *async)
{
int rc = SLURM_SUCCESS;
/* use user id */
// if ( strcmp(job_ptr->user_name, "fwinkler") != 0 &&
// strcmp(job_ptr->user_name, "rotscher") != 0 )
// return rc;
slurm_info(PLUGIN_NAME "prep_p_epilog_slurmctld\n");
char *job_data = xmalloc(sizeof(char) * STRING_LEN);
job_data_epilog(job_ptr, &job_data);
*async = have_epilog_slurmctld;
if (*async) {
/* MUST run before async task finishes */
epilog_slurmctld_callback(rc, job_ptr->job_id);
}
// Some async task
if (rc == SLURM_SUCCESS) {
pika_log(job_ptr->job_id, job_data, true);
}
return rc;
}
static void job_state(job_record_t *job_ptr, char **state)
{
if ( IS_JOB_RUNNING(job_ptr) )
sprintf(*state, "running");
else if ( IS_JOB_COMPLETE(job_ptr) )
sprintf(*state, "completed");
else if ( IS_JOB_CANCELLED(job_ptr) )
sprintf(*state, "cancelled");
else if ( IS_JOB_TIMEOUT(job_ptr) )
sprintf(*state, "timeout");
else if ( IS_JOB_OOM(job_ptr) )
sprintf(*state, "OOM");
else
sprintf(*state, "failed");
}
static void job_data_prolog(job_record_t *job_ptr, char **job_data)
{
// start
char time_str[32];
slurm_make_time_str((&job_ptr->start_time), time_str, 32);
snprintf(*job_data, STRING_LEN, "START_TIME = %s\n", time_str);
// partition
snprintf(*job_data + strlen(*job_data), STRING_LEN - strlen(*job_data), "PARTITION = %s\n", job_ptr->part_ptr->name);
// tres
snprintf(*job_data + strlen(*job_data), STRING_LEN - strlen(*job_data), "tres_fmt_alloc_str = %s\n", job_ptr->tres_fmt_alloc_str);
snprintf(*job_data + strlen(*job_data), STRING_LEN - strlen(*job_data), "tres_alloc_str = %s\n", job_ptr->tres_alloc_str);
// gres
snprintf(*job_data + strlen(*job_data), STRING_LEN - strlen(*job_data), "gres_alloc = %s\n", job_ptr->gres_alloc);
snprintf(*job_data + strlen(*job_data), STRING_LEN - strlen(*job_data), "gres_used = %s\n", job_ptr->gres_used);
snprintf(*job_data + strlen(*job_data), STRING_LEN - strlen(*job_data), "----");
}
static void job_data_epilog(job_record_t *job_ptr, char **job_data)
{
// state
char *state = (char *)xmalloc(10 * sizeof(char));
job_state(job_ptr, &state);
snprintf(*job_data, STRING_LEN, "JOB_STATE = %s\n", state);
xfree(state);
// start and end
char time_str[32];
slurm_make_time_str((&job_ptr->start_time), time_str, 32);
snprintf(*job_data + strlen(*job_data), STRING_LEN - strlen(*job_data), "START_TIME = %s\n", time_str);
slurm_make_time_str((&job_ptr->end_time), time_str, 32);
snprintf(*job_data + strlen(*job_data), STRING_LEN - strlen(*job_data), "END_TIME = %s\n", time_str);
snprintf(*job_data + strlen(*job_data), STRING_LEN - strlen(*job_data), "----");
}
static int pika_log(int job_id, char *job_data, bool is_epilog)
{
FILE *fp;
int rc = SLURM_SUCCESS;
char file_path[100];
sprintf(file_path, "var/log/slurm/pika.log");
slurm_mutex_lock(&plugin_log_lock);
fp = fopen(file_path, "a");
if ( fp == NULL )
return (-1);
if ( !is_epilog ) {
fprintf(fp, "PROLOG %d\n", job_id);
} else {
fprintf(fp, "EPILOG %d\n", job_id);
}
fprintf(fp, "%s\n", job_data);
xfree(job_data);
fclose(fp);
slurm_mutex_unlock(&plugin_log_lock);
return rc;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment