/*****************************************************************************\
* ext_sensors_rrd.c - slurm external sensors plugin for rrd.
*****************************************************************************
* Copyright (C) 2013
* Written by Bull- Thomas Cadeau/Martin Perry/Yiannis Georgiou
*
* This file is part of Slurm, a resource management program.
* For details, see .
* Please also read the included file: DISCLAIMER.
*
* Slurm 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 2 of the License, or (at your option)
* any later version.
*
* In addition, as a special exception, the copyright holders give permission
* to link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two. You must obey the GNU
* General Public License in all respects for all of the code used other than
* OpenSSL. If you modify file(s) with this exception, you may extend this
* exception to your version of the file(s), but you are not obligated to do
* so. If you do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source files in
* the program, then also delete it here.
*
* Slurm 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 Slurm; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
\*****************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/* slurm_xlator.h must be first */
#include "src/common/slurm_xlator.h"
#include "ext_sensors_rrd.h"
#include "src/common/fd.h"
#include "src/common/read_config.h"
#include "src/common/slurm_protocol_api.h"
#include "src/common/slurm_protocol_defs.h"
#include "src/common/slurm_ext_sensors.h"
#include "src/slurmd/common/proctrack.h"
#include
enum ext_sensors_value_type {
EXT_SENSORS_VALUE_ENERGY,
EXT_SENSORS_VALUE_TEMPERATURE,
};
#define _WATT_MIN 10
#define _WATT_MAX 500
#define _TEMP_MIN 1
#define _TEMP_MAX 300
/*
* 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 the 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
*
* /
*
* where is a description of the intended application of
* the plugin (e.g., "jobacct" for Slurm job completion logging) and
* is a description of how this plugin satisfies that application. Slurm will
* only load job completion logging plugins if the plugin_type string has a
* prefix of "jobacct/".
*
* plugin_version - an unsigned 32-bit integer containing the Slurm version
* (major.minor.micro combined into a single number).
*/
const char plugin_name[] = "ExtSensors rrd plugin";
const char plugin_type[] = "ext_sensors/rrd";
const uint32_t plugin_version = SLURM_VERSION_NUMBER;
static ext_sensors_conf_t ext_sensors_conf;
static ext_sensors_conf_t *ext_sensors_cnf = &ext_sensors_conf;
static time_t last_valid_time;
static rrd_value_t last_valid_watt;
/* Local plugin functions */
static int _update_node_data(void);
static int _update_switch_data(void);
static int _update_door_data(void);
extern int _ext_sensors_read_conf(void);
static void _ext_sensors_clear_free_conf(void);
/* Local RRD functions */
static rrd_value_t _get_additional_consumption(time_t time0, time_t time1,
rrd_value_t watt0,
rrd_value_t watt1);
static rrd_value_t _validate_watt(rrd_value_t *v);
static char* _get_node_rrd_path(char* component_name,
enum ext_sensors_value_type sensor_type);
static uint32_t _rrd_get_last_one(char* filename, char* rra_name);
static uint64_t _rrd_consolidate_one(time_t t0, time_t t1,
char* filename, char* rra_name,
bool flag_approximate);
static rrd_value_t _get_additional_consumption(time_t time0, time_t time1,
rrd_value_t watt0,
rrd_value_t watt1)
{
rrd_value_t consumption = (time1 - time0)*(watt1 + watt0)/2;
return consumption;
}
static rrd_value_t _validate_watt(rrd_value_t *v)
{
rrd_value_t r = (rrd_value_t)NO_VAL;
if (v != NULL &&
*v > ext_sensors_cnf->min_watt &&
*v < ext_sensors_cnf->max_watt)
r = *v;
return r;
}
static char* _get_node_rrd_path(char* component_name,
enum ext_sensors_value_type sensor_type)
{
char *p;
char *rrd_file;
struct stat buf;
switch (sensor_type) {
case EXT_SENSORS_VALUE_ENERGY:
rrd_file = ext_sensors_cnf->energy_rrd_file;
break;
case EXT_SENSORS_VALUE_TEMPERATURE:
rrd_file = ext_sensors_cnf->temp_rrd_file;
break;
default:
error("ext_sensors: _get_node_rrd_path: unknown enum %d",
sensor_type);
return NULL;
}
if (!component_name || !strlen(component_name) || !rrd_file)
return NULL;
p = xstrdup(rrd_file);
xstrsubstitute(p, "%n", component_name);
if (!xstrcmp(p, rrd_file)) {
xfree(p);
return NULL;
}
if (stat(p, &buf) == -1) {
xfree(p);
return NULL;
}
return p;
}
static uint32_t _rrd_get_last_one(char* filename, char* rra_name)
{
/* RRD library usage notes:
* do not use the following lines for compatibility:
* 1.3.8-6 : (argv={lastupdate, filename}
* status = rrd_lastupdate(argc, argv, &time, &ds_count,
* &ds_names, &last_ds);
* 1.4.7 :
* status = rrd_lastupdate_r(filename, &time, &ds_count,
* &ds_names, &last_ds);
*/
rrd_info_t *data, *data_p;
char line[] = "ds[%s].last_ds", *p, *rra = NULL;
char *argv[] = {"info", filename, NULL};
uint32_t temperature = NO_VAL;
p = xstrdup(line);
data = rrd_info(2, argv);
data_p = data;
if (rra_name == NULL) {
while (data_p) {
if (!xstrncmp(line, data_p->key, 3)) {
rra = xstrdup(data_p->key + 3);
xstrsubstitute(rra, strchr(rra, ']'), "");
break;
}
data_p = data_p->next;
}
} else
rra = rra_name;
if (rra != NULL) {
xstrsubstitute(p, "%s", rra_name);
if (rra_name == NULL)
xfree(rra);
if (xstrcmp(p,line) == 0) {
xfree(p);
rrd_info_free(data);
return temperature;
}
} else {
xfree(p);
rrd_info_free(data);
return temperature;
}
while (data_p) {
if (!xstrcmp(p, data_p->key)) {
if (!sscanf(data_p->value.u_str, "%d", &temperature))
temperature = 1;
break;
}
data_p = data_p->next;
}
xfree(p);
rrd_info_free(data);
return temperature;
}
static uint64_t _rrd_consolidate_one(time_t t0, time_t t1,
char* filename, char* rra_name,
bool flag_approximate)
{
int status, rra_nb = -1;
unsigned long step = 1, ds_count, ii;
char cf[] = "AVERAGE";
char **ds_names;
time_t ti, start = t0-1, end = t1+1;
uint32_t nb_miss = 0, nb_values = 0;
rrd_value_t *rrd_data, *rrd_data_p;
rrd_value_t current_watt = (rrd_value_t)NO_VAL;
rrd_value_t temp_energy = 0, consumed_energy = 0;
last_valid_time = 0;
last_valid_watt = (rrd_value_t)NO_VAL;
status = rrd_fetch_r(filename, cf,
&start, &end, &step,
&ds_count, &ds_names,
&rrd_data);
if (status != 0){
log_flag(EXT_SENSORS, "ext_sensors: error rrd_fetch %s",
filename);
return NO_VAL64;
}
rrd_data_p = rrd_data;
do {
if (start == end) {
consumed_energy = (rrd_value_t)NO_VAL64;
break;
}
if (ds_count == 0) {
log_flag(EXT_SENSORS, "ext_sensors: error ds_count==0 in RRD %s",
filename);
consumed_energy = (rrd_value_t)NO_VAL64;
break;
} else if (ds_count == 1 || rra_name == NULL)
rra_nb = 0;
else {
for (ii = 0; ii < ds_count; ii++){
if (!xstrcmp(ds_names[ii],rra_name)) {
rra_nb = ii;
break;
}
}
if (rra_nb == -1) {
log_flag(EXT_SENSORS, "ext_sensors: error RRA %s not found in RRD %s",
rra_name, filename);
consumed_energy = (rrd_value_t)NO_VAL64;
break;
}
}
ti = start;
do {
for (ii = 0; ii < rra_nb; ii++)
rrd_data_p++;
last_valid_watt = _validate_watt(rrd_data_p);
if (last_valid_watt != (rrd_value_t)NO_VAL)
last_valid_time = ti;
for (ii = rra_nb; ii < ds_count; ii++)
rrd_data_p++;
ti += step;
} while (ti < t0 && ti < end);
if (ti != t0 && ti < end) {
for (ii = 0; ii < rra_nb; ii++)
rrd_data_p++;
current_watt = _validate_watt(rrd_data_p);
if (current_watt != (rrd_value_t)NO_VAL) {
temp_energy = _get_additional_consumption(
t0, ti < t1 ? ti : t1,
current_watt, current_watt);
last_valid_watt = current_watt;
last_valid_time = ti;
consumed_energy += temp_energy;
nb_values += 1;
} else {
nb_miss += 10001;
}
for (ii = rra_nb; ii < ds_count; ii++)
rrd_data_p++;
} else if ((ti == t0) && (ti < end)) {
for (ii = 0; ii < rra_nb; ii++)
rrd_data_p++;
current_watt = _validate_watt(rrd_data_p);
if (current_watt != (rrd_value_t)NO_VAL) {
last_valid_watt = current_watt;
last_valid_time = ti;
}
for (ii = rra_nb; ii < ds_count; ii++)
rrd_data_p++;
ti += step;
}
while (((ti += step) <= t1) && (ti < end)) {
for (ii = 0; ii < rra_nb; ii++)
rrd_data_p++;
current_watt = _validate_watt(rrd_data_p);
if (current_watt != (rrd_value_t)NO_VAL &&
last_valid_watt != (rrd_value_t)NO_VAL) {
temp_energy = _get_additional_consumption(
ti-step, ti,
last_valid_watt, current_watt);
last_valid_watt = current_watt;
last_valid_time = ti;
consumed_energy += temp_energy;
nb_values += 1;
} else {
nb_miss += 1;
}
for (ii = rra_nb; ii < ds_count; ii++)
rrd_data_p++;
}
if ((ti > t1) && (t1 > (t0 + step)) && (ti-step < t1)) {
if (current_watt != (rrd_value_t)NO_VAL) {
temp_energy = _get_additional_consumption(
ti-step, t1,
current_watt, current_watt);
consumed_energy += temp_energy;
nb_values += 1;
} else {
nb_miss += 1;
}
}
} while(0);
if (nb_miss >= 10000) {
log_flag(EXT_SENSORS, "ext_sensors: RRD: no first value");
nb_miss -= 10000;
}
log_flag(EXT_SENSORS, "ext_sensors: RRD: have %d values and miss %d values",
nb_values, nb_miss);
if (flag_approximate &&
current_watt == (rrd_value_t)NO_VAL &&
last_valid_watt != (rrd_value_t)NO_VAL) {
temp_energy = _get_additional_consumption(
last_valid_time, t1,
last_valid_watt, last_valid_watt);
consumed_energy += temp_energy;
}
for (ii = 0; ii < ds_count; ii++)
free(ds_names[ii]);
free(ds_names);
free(rrd_data);
return (uint64_t)consumed_energy;
}
extern uint64_t RRD_consolidate(time_t step_starttime, time_t step_endtime,
bitstr_t* bitmap_of_nodes)
{
uint64_t consumed_energy = 0;
uint64_t tmp;
char *node_name = NULL;
hostlist_t hl;
char* path;
node_name = bitmap2node_name(bitmap_of_nodes);
hl = hostlist_create(node_name);
xfree(node_name);
while ((node_name = hostlist_shift(hl))) {
if (!(path = _get_node_rrd_path(node_name,
EXT_SENSORS_VALUE_ENERGY)))
consumed_energy = NO_VAL64;
free(node_name);
if ((tmp = _rrd_consolidate_one(
step_starttime, step_endtime, path,
ext_sensors_cnf->energy_rra_name, true))
== NO_VAL64)
consumed_energy = NO_VAL64;
xfree(path);
if (consumed_energy == NO_VAL64)
break;
consumed_energy += tmp;
}
hostlist_destroy(hl);
return consumed_energy;
}
static int _update_node_data(void)
{
int i;
char* path;
uint32_t tmp32;
uint64_t tmp;
ext_sensors_data_t *ext_sensors;
time_t now = time(NULL);
if (ext_sensors_cnf->dataopts & EXT_SENSORS_OPT_NODE_ENERGY) {
for (i=0; i < node_record_count; i++) {
ext_sensors = node_record_table_ptr[i].ext_sensors;
if (ext_sensors->energy_update_time == 0) {
ext_sensors->energy_update_time = now;
ext_sensors->consumed_energy = 0;
ext_sensors->current_watts = 0;
continue;
}
if (!(path = _get_node_rrd_path(
node_record_table_ptr[i].name,
EXT_SENSORS_VALUE_ENERGY))) {
ext_sensors->consumed_energy = NO_VAL64;
ext_sensors->current_watts = NO_VAL;
continue;
}
tmp = _rrd_consolidate_one(
ext_sensors->energy_update_time,
now, path,
ext_sensors_cnf->energy_rra_name,
false);
xfree(path);
if ((tmp != (uint64_t)NO_VAL) && (tmp != 0) &&
(last_valid_time != 0) &&
(last_valid_watt != (rrd_value_t)NO_VAL)) {
if ((ext_sensors->consumed_energy <= 0) ||
(ext_sensors->consumed_energy ==
NO_VAL64)) {
ext_sensors->consumed_energy = tmp;
} else {
ext_sensors->consumed_energy += tmp;
}
ext_sensors->energy_update_time =
last_valid_time;
ext_sensors->current_watts =
(uint32_t)last_valid_watt;
}
}
}
if (ext_sensors_cnf->dataopts & EXT_SENSORS_OPT_NODE_TEMP) {
for (i=0; i < node_record_count; i++) {
ext_sensors = node_record_table_ptr[i].ext_sensors;
if (!(path = _get_node_rrd_path(
node_record_table_ptr[i].name,
EXT_SENSORS_VALUE_TEMPERATURE))) {
ext_sensors->temperature = NO_VAL;
continue;
}
tmp32 = _rrd_get_last_one(
path, ext_sensors_cnf->temp_rra_name);
xfree(path);
if (tmp32 != NO_VAL &&
tmp32 > ext_sensors_cnf->min_temp &&
tmp32 < ext_sensors_cnf->max_temp) {
ext_sensors->temperature = tmp32;
} else {
ext_sensors->temperature = NO_VAL;
}
}
}
return SLURM_SUCCESS;
}
static int _update_switch_data(void)
{
/* TODO: insert code here to do the following:
* If SwitchData is configured in ext_sensors_cnf->dataopts:
* for each switch, update data in switch_record from RRD database */
return SLURM_SUCCESS;
}
static int _update_door_data(void)
{
/* TODO: insert code here to do the following:
* If ColdDoorData is configured in ext_sensors_cnf->dataopts:
* for each door, update data in door_record from RRD database */
return SLURM_SUCCESS;
}
extern int _ext_sensors_read_conf(void)
{
s_p_options_t options[] = {
{"JobData", S_P_STRING},
{"NodeData", S_P_STRING},
{"SwitchData", S_P_STRING},
{"ColdDoorData", S_P_STRING},
{"MinWatt", S_P_UINT32},
{"MaxWatt", S_P_UINT32},
{"MinTemp", S_P_UINT32},
{"MaxTemp", S_P_UINT32},
{"EnergyRRA", S_P_STRING},
{"TempRRA", S_P_STRING},
{"EnergyPathRRD", S_P_STRING},
{"TempPathRRD", S_P_STRING},
{NULL} };
s_p_hashtbl_t *tbl = NULL;
char *conf_path = NULL;
struct stat buf;
char *temp_str = NULL;
/* Set initial values */
if (ext_sensors_cnf == NULL) {
return SLURM_ERROR;
}
_ext_sensors_clear_free_conf();
/* Get the ext_sensors.conf path and validate the file */
conf_path = get_extra_conf_path("ext_sensors.conf");
if ((conf_path == NULL) || (stat(conf_path, &buf) == -1)) {
fatal("ext_sensors: No ext_sensors file (%s)", conf_path);
} else {
debug2("ext_sensors: Reading ext_sensors file %s", conf_path);
tbl = s_p_hashtbl_create(options);
if (s_p_parse_file(tbl, NULL, conf_path, false) ==
SLURM_ERROR) {
fatal("ext_sensors: Could not open/read/parse "
"ext_sensors file %s", conf_path);
}
/* ext_sensors initialization parameters */
if (s_p_get_string(&temp_str, "JobData", tbl)) {
if (strstr(temp_str, "energy"))
ext_sensors_cnf->dataopts
|= EXT_SENSORS_OPT_JOB_ENERGY;
}
xfree(temp_str);
if (s_p_get_string(&temp_str, "NodeData", tbl)) {
if (strstr(temp_str, "energy"))
ext_sensors_cnf->dataopts
|= EXT_SENSORS_OPT_NODE_ENERGY;
if (strstr(temp_str, "temp"))
ext_sensors_cnf->dataopts
|= EXT_SENSORS_OPT_NODE_TEMP;
}
xfree(temp_str);
if (s_p_get_string(&temp_str, "SwitchData", tbl)) {
if (strstr(temp_str, "energy"))
ext_sensors_cnf->dataopts
|= EXT_SENSORS_OPT_SWITCH_ENERGY;
if (strstr(temp_str, "temp"))
ext_sensors_cnf->dataopts
|= EXT_SENSORS_OPT_SWITCH_TEMP;
}
xfree(temp_str);
if (s_p_get_string(&temp_str, "ColdDoorData", tbl)) {
if (strstr(temp_str, "temp"))
ext_sensors_cnf->dataopts
|= EXT_SENSORS_OPT_COLDDOOR_TEMP;
}
xfree(temp_str);
s_p_get_uint32(&ext_sensors_cnf->min_watt,"MinWatt", tbl);
s_p_get_uint32(&ext_sensors_cnf->max_watt,"MaxWatt", tbl);
s_p_get_uint32(&ext_sensors_cnf->min_temp,"MinTemp", tbl);
s_p_get_uint32(&ext_sensors_cnf->max_temp,"MaxTemp", tbl);
if (!s_p_get_string(&ext_sensors_cnf->energy_rra_name,
"EnergyRRA", tbl)) {
if (ext_sensors_cnf->dataopts
& EXT_SENSORS_OPT_JOB_ENERGY)
fatal("ext_sensors/rrd: EnergyRRA "
"must be set to gather JobData=energy. "
"Please set this value in your "
"ext_sensors.conf file.");
}
if (!s_p_get_string(&ext_sensors_cnf->temp_rra_name,
"TempRRA", tbl)) {
if (ext_sensors_cnf->dataopts
& EXT_SENSORS_OPT_NODE_TEMP)
fatal("ext_sensors/rrd: TempRRA "
"must be set to gather NodeData=temp. "
"Please set this value in your "
"ext_sensors.conf file.");
}
s_p_get_string(&ext_sensors_cnf->energy_rrd_file,
"EnergyPathRRD", tbl);
s_p_get_string(&ext_sensors_cnf->temp_rrd_file,
"TempPathRRD", tbl);
s_p_hashtbl_destroy(tbl);
}
xfree(conf_path);
return SLURM_SUCCESS;
}
static void _ext_sensors_clear_free_conf(void)
{
ext_sensors_cnf->dataopts = 0;
ext_sensors_cnf->min_watt = _WATT_MIN;
ext_sensors_cnf->max_watt = _WATT_MAX;
ext_sensors_cnf->min_temp = _TEMP_MIN;
ext_sensors_cnf->max_temp = _TEMP_MAX;
xfree(ext_sensors_cnf->energy_rra_name);
xfree(ext_sensors_cnf->temp_rra_name);
xfree(ext_sensors_cnf->energy_rrd_file);
xfree(ext_sensors_cnf->temp_rrd_file);
}
extern int ext_sensors_p_update_component_data(void)
{
int rc_node, rc_switch, rc_door;
rc_node = _update_node_data();
rc_switch = _update_switch_data();
rc_door = _update_door_data();
if ((rc_node == SLURM_SUCCESS) &&
(rc_switch == SLURM_SUCCESS) &&
(rc_door == SLURM_SUCCESS))
return SLURM_SUCCESS;
return SLURM_ERROR;
}
extern int ext_sensors_p_get_stepstartdata(step_record_t *step_rec)
{
/* Nothing to do here for ext_sensors/rrd plugin */
int rc = SLURM_SUCCESS;
return rc;
}
extern int ext_sensors_p_get_stependdata(step_record_t *step_rec)
{
time_t step_endtime = time(NULL);
int rc = SLURM_SUCCESS;
if (ext_sensors_cnf->dataopts & EXT_SENSORS_OPT_JOB_ENERGY) {
step_rec->ext_sensors->consumed_energy =
RRD_consolidate(step_rec->start_time, step_endtime,
step_rec->step_node_bitmap);
if (step_rec->jobacct &&
(!step_rec->jobacct->energy.consumed_energy
|| (step_rec->jobacct->energy.consumed_energy ==
NO_VAL64))) {
step_rec->jobacct->energy.consumed_energy =
step_rec->ext_sensors->consumed_energy;
}
}
return rc;
}
extern List ext_sensors_p_get_config(void)
{
config_key_pair_t *key_pair;
List ext_list = list_create(destroy_config_key_pair);
char *sep = ", ";
char *tmp_val = NULL;
if (ext_sensors_cnf->dataopts & EXT_SENSORS_OPT_JOB_ENERGY) {
key_pair = xmalloc(sizeof(config_key_pair_t));
key_pair->name = xstrdup("JobData");
key_pair->value = xstrdup("energy");
list_append(ext_list, key_pair);
}
if (ext_sensors_cnf->dataopts & EXT_SENSORS_OPT_NODE_ENERGY)
tmp_val = xstrdup("energy");
if (ext_sensors_cnf->dataopts & EXT_SENSORS_OPT_NODE_TEMP) {
if (tmp_val)
xstrcat(tmp_val, sep);
xstrcat(tmp_val, "temp");
}
key_pair = xmalloc(sizeof(config_key_pair_t));
key_pair->name = xstrdup("NodeData");
key_pair->value = tmp_val;
list_append(ext_list, key_pair);
tmp_val = NULL;
if (ext_sensors_cnf->dataopts & EXT_SENSORS_OPT_SWITCH_ENERGY)
tmp_val = xstrdup("energy");
if (ext_sensors_cnf->dataopts & EXT_SENSORS_OPT_SWITCH_TEMP) {
if (tmp_val)
xstrcat(tmp_val, sep);
xstrcat(tmp_val, "temp");
}
key_pair = xmalloc(sizeof(config_key_pair_t));
key_pair->name = xstrdup("SwitchData");
key_pair->value = tmp_val;
list_append(ext_list, key_pair);
tmp_val = NULL;
if (ext_sensors_cnf->dataopts & EXT_SENSORS_OPT_COLDDOOR_TEMP) {
key_pair = xmalloc(sizeof(config_key_pair_t));
key_pair->name = xstrdup("ColdDoorData");
key_pair->value = xstrdup("temp");
list_append(ext_list, key_pair);
}
key_pair = xmalloc(sizeof(config_key_pair_t));
key_pair->name = xstrdup("MinWatt");
key_pair->value = xstrdup_printf("%u", ext_sensors_cnf->min_watt);
list_append(ext_list, key_pair);
key_pair = xmalloc(sizeof(config_key_pair_t));
key_pair->name = xstrdup("MaxWatt");
key_pair->value = xstrdup_printf("%u", ext_sensors_cnf->max_watt);
list_append(ext_list, key_pair);
key_pair = xmalloc(sizeof(config_key_pair_t));
key_pair->name = xstrdup("MinTemp");
key_pair->value = xstrdup_printf("%u", ext_sensors_cnf->min_temp);
list_append(ext_list, key_pair);
key_pair = xmalloc(sizeof(config_key_pair_t));
key_pair->name = xstrdup("MaxTemp");
key_pair->value = xstrdup_printf("%u", ext_sensors_cnf->max_temp);
list_append(ext_list, key_pair);
key_pair = xmalloc(sizeof(config_key_pair_t));
key_pair->name = xstrdup("EnergyRRA");
key_pair->value = xstrdup(ext_sensors_cnf->energy_rra_name);
list_append(ext_list, key_pair);
key_pair = xmalloc(sizeof(config_key_pair_t));
key_pair->name = xstrdup("TempRRA");
key_pair->value = xstrdup(ext_sensors_cnf->temp_rra_name);
list_append(ext_list, key_pair);
key_pair = xmalloc(sizeof(config_key_pair_t));
key_pair->name = xstrdup("EnergyPathRRD");
key_pair->value = xstrdup(ext_sensors_cnf->energy_rrd_file);
list_append(ext_list, key_pair);
key_pair = xmalloc(sizeof(config_key_pair_t));
key_pair->name = xstrdup("TempPathRRD");
key_pair->value = xstrdup(ext_sensors_cnf->temp_rrd_file);
list_append(ext_list, key_pair);
list_sort(ext_list, (ListCmpF) sort_key_pairs);
return ext_list;
}
/*
* init() is called when the plugin is loaded, before any other functions
* are called. Put global initialization here.
*/
extern int init(void)
{
/* read ext_sensors configuration */
if (_ext_sensors_read_conf())
return SLURM_ERROR;
verbose("%s loaded", plugin_name);
return SLURM_SUCCESS;
}
extern int fini(void)
{
_ext_sensors_clear_free_conf();
return SLURM_SUCCESS;
}