summaryrefslogtreecommitdiffstats
path: root/collectors/freeipmi.plugin
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--collectors/freeipmi.plugin/freeipmi_plugin.c244
-rw-r--r--collectors/freeipmi.plugin/integrations/intelligent_platform_management_interface_ipmi.md49
2 files changed, 240 insertions, 53 deletions
diff --git a/collectors/freeipmi.plugin/freeipmi_plugin.c b/collectors/freeipmi.plugin/freeipmi_plugin.c
index 63147d621..6ec9b698b 100644
--- a/collectors/freeipmi.plugin/freeipmi_plugin.c
+++ b/collectors/freeipmi.plugin/freeipmi_plugin.c
@@ -22,6 +22,10 @@
#include "libnetdata/libnetdata.h"
#include "libnetdata/required_dummies.h"
+#define FREEIPMI_GLOBAL_FUNCTION_SENSORS() do { \
+ fprintf(stdout, PLUGINSD_KEYWORD_FUNCTION " GLOBAL \"ipmi-sensors\" %d \"%s\"\n", 5, "Displays current sensor state and readings"); \
+ } while(0)
+
// component names, based on our patterns
#define NETDATA_SENSOR_COMPONENT_MEMORY_MODULE "Memory Module"
#define NETDATA_SENSOR_COMPONENT_MEMORY "Memory"
@@ -83,6 +87,12 @@ static void netdata_update_ipmi_sel_events_count(struct netdata_ipmi_state *stat
/* Communication Configuration - Initialize accordingly */
+static netdata_mutex_t stdout_mutex = NETDATA_MUTEX_INITIALIZER;
+static bool function_plugin_should_exit = false;
+
+int update_every = IPMI_SENSORS_MIN_UPDATE_EVERY; // this is the minimum update frequency
+int update_every_sel = IPMI_SEL_MIN_UPDATE_EVERY; // this is the minimum update frequency for SEL events
+
/* Hostname, NULL for In-band communication, non-null for a hostname */
char *hostname = NULL;
@@ -707,6 +717,8 @@ struct netdata_ipmi_state {
} updates;
};
+struct netdata_ipmi_state state = {0};
+
// ----------------------------------------------------------------------------
// excluded record ids maintenance (both for sensor data and state)
@@ -1297,6 +1309,7 @@ static size_t send_ipmi_sensor_metrics_to_netdata(struct netdata_ipmi_state *sta
int update_every = (int)(state->sensors.freq_ut / USEC_PER_SEC);
struct sensor *sn;
+ netdata_mutex_lock(&stdout_mutex);
// generate the CHART/DIMENSION lines, if we have to
dfe_start_reentrant(state->sensors.dict, sn) {
if(unlikely(!sn->do_metric && !sn->do_state))
@@ -1396,12 +1409,16 @@ static size_t send_ipmi_sensor_metrics_to_netdata(struct netdata_ipmi_state *sta
}
dfe_done(sn);
+ netdata_mutex_unlock(&stdout_mutex);
+
return total_sensors_sent;
}
static size_t send_ipmi_sel_metrics_to_netdata(struct netdata_ipmi_state *state) {
static bool sel_chart_generated = false;
+ netdata_mutex_lock(&stdout_mutex);
+
if(likely(state->sel.status == ICS_RUNNING)) {
if(unlikely(!sel_chart_generated)) {
sel_chart_generated = true;
@@ -1422,39 +1439,197 @@ static size_t send_ipmi_sel_metrics_to_netdata(struct netdata_ipmi_state *state)
);
}
+ netdata_mutex_unlock(&stdout_mutex);
+
return state->sel.events;
}
// ----------------------------------------------------------------------------
-// main, command line arguments parsing
-int main (int argc, char **argv) {
- bool netdata_do_sel = IPMI_ENABLE_SEL_BY_DEFAULT;
+static const char *get_sensor_state_string(struct sensor *sn) {
+ switch (sn->sensor_state) {
+ case IPMI_MONITORING_STATE_NOMINAL:
+ return "nominal";
+ case IPMI_MONITORING_STATE_WARNING:
+ return "warning";
+ case IPMI_MONITORING_STATE_CRITICAL:
+ return "critical";
+ default:
+ return "unknown";
+ }
+}
- stderror = stderr;
- clocks_init();
+static const char *get_sensor_function_priority(struct sensor *sn) {
+ switch (sn->sensor_state) {
+ case IPMI_MONITORING_STATE_WARNING:
+ return "warning";
+ case IPMI_MONITORING_STATE_CRITICAL:
+ return "critical";
+ default:
+ return "normal";
+ }
+}
- int update_every = IPMI_SENSORS_MIN_UPDATE_EVERY; // this is the minimum update frequency
- int update_every_sel = IPMI_SEL_MIN_UPDATE_EVERY; // this is the minimum update frequency for SEL events
- bool debug = false;
+static void freeimi_function_sensors(const char *transaction, char *function __maybe_unused, int timeout __maybe_unused, bool *cancelled __maybe_unused) {
+ time_t expires = now_realtime_sec() + update_every;
- // ------------------------------------------------------------------------
- // initialization of netdata plugin
+ BUFFER *wb = buffer_create(PLUGINSD_LINE_MAX, NULL);
+ buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_NEWLINE_ON_ARRAY_ITEMS);
+ buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
+ buffer_json_member_add_string(wb, "type", "table");
+ buffer_json_member_add_time_t(wb, "update_every", update_every);
+ buffer_json_member_add_string(wb, "help", "View IPMI sensor readings and its state");
+ buffer_json_member_add_array(wb, "data");
- program_name = "freeipmi.plugin";
+ struct sensor *sn;
+ dfe_start_reentrant(state.sensors.dict, sn) {
+ if (unlikely(!sn->do_metric && !sn->do_state))
+ continue;
+
+ double reading = NAN;
+ switch (sn->sensor_reading_type) {
+ case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER32:
+ reading = (double)sn->sensor_reading.uint32_value;
+ break;
+ case IPMI_MONITORING_SENSOR_READING_TYPE_DOUBLE:
+ reading = (double)(sn->sensor_reading.double_value);
+ break;
+ case IPMI_MONITORING_SENSOR_READING_TYPE_UNSIGNED_INTEGER8_BOOL:
+ reading = (double)sn->sensor_reading.bool_value;
+ break;
+ }
- // disable syslog
- error_log_syslog = 0;
+ buffer_json_add_array_item_array(wb);
- // set errors flood protection to 100 logs per hour
- error_log_errors_per_period = 100;
- error_log_throttle_period = 3600;
+ buffer_json_add_array_item_string(wb, sn->sensor_name);
+ buffer_json_add_array_item_string(wb, sn->type);
+ buffer_json_add_array_item_string(wb, sn->component);
+ buffer_json_add_array_item_double(wb, reading);
+ buffer_json_add_array_item_string(wb, sn->units);
+ buffer_json_add_array_item_string(wb, get_sensor_state_string(sn));
- log_set_global_severity_for_external_plugins();
+ buffer_json_add_array_item_object(wb);
+ buffer_json_member_add_string(wb, "severity", get_sensor_function_priority(sn));
+ buffer_json_object_close(wb);
- // initialize the threads
+ buffer_json_array_close(wb);
+ }
+ dfe_done(sn);
+
+ buffer_json_array_close(wb); // data
+ buffer_json_member_add_object(wb, "columns");
+ {
+ size_t field_id = 0;
+
+ buffer_rrdf_table_add_field(wb, field_id++, "Sensor", "Sensor Name",
+ RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
+ 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
+ RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
+ RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_UNIQUE_KEY | RRDF_FIELD_OPTS_STICKY | RRDF_FIELD_OPTS_FULL_WIDTH,
+ NULL);
+ buffer_rrdf_table_add_field(wb, field_id++, "Type", "Sensor Type",
+ RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
+ 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
+ RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
+ RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_UNIQUE_KEY,
+ NULL);
+ buffer_rrdf_table_add_field(wb, field_id++, "Component", "Sensor Component",
+ RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
+ 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
+ RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
+ RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_UNIQUE_KEY,
+ NULL);
+ buffer_rrdf_table_add_field(wb, field_id++, "Reading", "Sensor Current Reading",
+ RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NUMBER,
+ 2, NULL, 0, RRDF_FIELD_SORT_DESCENDING, NULL,
+ RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
+ RRDF_FIELD_OPTS_VISIBLE,
+ NULL);
+ buffer_rrdf_table_add_field(wb, field_id++, "Units", "Sensor Reading Units",
+ RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
+ 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
+ RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
+ RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_UNIQUE_KEY,
+ NULL);
+ buffer_rrdf_table_add_field(wb, field_id++, "State", "Sensor State",
+ RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
+ 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
+ RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
+ RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_UNIQUE_KEY,
+ NULL);
+ buffer_rrdf_table_add_field(
+ wb, field_id++,
+ "rowOptions", "rowOptions",
+ RRDF_FIELD_TYPE_NONE,
+ RRDR_FIELD_VISUAL_ROW_OPTIONS,
+ RRDF_FIELD_TRANSFORM_NONE, 0, NULL, NAN,
+ RRDF_FIELD_SORT_FIXED,
+ NULL,
+ RRDF_FIELD_SUMMARY_COUNT,
+ RRDF_FIELD_FILTER_NONE,
+ RRDF_FIELD_OPTS_DUMMY,
+ NULL);
+ }
+
+ buffer_json_object_close(wb); // columns
+ buffer_json_member_add_string(wb, "default_sort_column", "Type");
+
+ buffer_json_member_add_object(wb, "charts");
+ {
+ buffer_json_member_add_object(wb, "Sensors");
+ {
+ buffer_json_member_add_string(wb, "name", "Sensors");
+ buffer_json_member_add_string(wb, "type", "stacked-bar");
+ buffer_json_member_add_array(wb, "columns");
+ {
+ buffer_json_add_array_item_string(wb, "Sensor");
+ }
+ buffer_json_array_close(wb);
+ }
+ buffer_json_object_close(wb);
+ }
+ buffer_json_object_close(wb); // charts
+
+ buffer_json_member_add_array(wb, "default_charts");
+ {
+ buffer_json_add_array_item_array(wb);
+ buffer_json_add_array_item_string(wb, "Sensors");
+ buffer_json_add_array_item_string(wb, "Component");
+ buffer_json_array_close(wb);
+
+ buffer_json_add_array_item_array(wb);
+ buffer_json_add_array_item_string(wb, "Sensors");
+ buffer_json_add_array_item_string(wb, "State");
+ buffer_json_array_close(wb);
+ }
+ buffer_json_array_close(wb);
+
+ buffer_json_member_add_time_t(wb, "expires", now_realtime_sec() + 1);
+ buffer_json_finalize(wb);
+
+ pluginsd_function_result_to_stdout(transaction, HTTP_RESP_OK, "application/json", expires, wb);
+
+ buffer_free(wb);
+}
+
+// ----------------------------------------------------------------------------
+// main, command line arguments parsing
+
+static void plugin_exit(int code) {
+ fflush(stdout);
+ function_plugin_should_exit = true;
+ exit(code);
+}
+
+int main (int argc, char **argv) {
+ clocks_init();
+ nd_log_initialize_for_external_plugins("freeipmi.plugin");
netdata_threads_init_for_external_plugins(0); // set the default threads stack size here
+ bool netdata_do_sel = IPMI_ENABLE_SEL_BY_DEFAULT;
+
+ bool debug = false;
+
// ------------------------------------------------------------------------
// parse command line parameters
@@ -1728,7 +1903,7 @@ int main (int argc, char **argv) {
errno = 0;
if(freq_s && freq_s < update_every)
- collector_error("%s(): update frequency %d seconds is too small for IPMI. Using %d.",
+ collector_info("%s(): update frequency %d seconds is too small for IPMI. Using %d.",
__FUNCTION__, freq_s, update_every);
update_every = freq_s = MAX(freq_s, update_every);
@@ -1801,16 +1976,17 @@ int main (int argc, char **argv) {
heartbeat_t hb;
heartbeat_init(&hb);
+
for(iteration = 0; 1 ; iteration++) {
usec_t dt = heartbeat_next(&hb, step);
if (!tty) {
+ netdata_mutex_lock(&stdout_mutex);
fprintf(stdout, "\n"); // keepalive to avoid parser read timeout (2 minutes) during ipmi_detect_speed_secs()
fflush(stdout);
+ netdata_mutex_unlock(&stdout_mutex);
}
- struct netdata_ipmi_state state = {0 };
-
spinlock_lock(&sensors_data.spinlock);
state.sensors = sensors_data.state.sensors;
spinlock_unlock(&sensors_data.spinlock);
@@ -1827,8 +2003,7 @@ int main (int argc, char **argv) {
__FUNCTION__, (size_t)((now_monotonic_usec() - state.sensors.last_iteration_ut) / USEC_PER_SEC));
fprintf(stdout, "EXIT\n");
- fflush(stdout);
- exit(0);
+ plugin_exit(0);
}
break;
@@ -1838,14 +2013,12 @@ int main (int argc, char **argv) {
case ICS_INIT_FAILED:
collector_error("%s(): sensors failed to initialize. Calling DISABLE.", __FUNCTION__);
fprintf(stdout, "DISABLE\n");
- fflush(stdout);
- exit(0);
+ plugin_exit(0);
case ICS_FAILED:
collector_error("%s(): sensors fails repeatedly to collect metrics. Exiting to restart.", __FUNCTION__);
fprintf(stdout, "EXIT\n");
- fflush(stdout);
- exit(0);
+ plugin_exit(0);
}
if(netdata_do_sel) {
@@ -1865,6 +2038,16 @@ int main (int argc, char **argv) {
if(unlikely(debug))
fprintf(stderr, "%s: calling send_ipmi_sensor_metrics_to_netdata()\n", program_name);
+ static bool add_func_sensors = true;
+ if (add_func_sensors) {
+ add_func_sensors = false;
+ struct functions_evloop_globals *wg =
+ functions_evloop_init(1, "FREEIPMI", &stdout_mutex, &function_plugin_should_exit);
+ functions_evloop_add_function(
+ wg, "ipmi-sensors", freeimi_function_sensors, PLUGINS_FUNCTIONS_TIMEOUT_DEFAULT);
+ FREEIPMI_GLOBAL_FUNCTION_SENSORS();
+ }
+
state.updates.now_ut = now_monotonic_usec();
send_ipmi_sensor_metrics_to_netdata(&state);
@@ -1880,6 +2063,8 @@ int main (int argc, char **argv) {
, state.sensors.collected
);
+ netdata_mutex_lock(&stdout_mutex);
+
if (!global_chart_created) {
global_chart_created = true;
@@ -1899,10 +2084,11 @@ int main (int argc, char **argv) {
if (now_monotonic_sec() - started_t > IPMI_RESTART_EVERY_SECONDS) {
collector_info("%s(): reached my lifetime expectancy. Exiting to restart.", __FUNCTION__);
fprintf(stdout, "EXIT\n");
- fflush(stdout);
- exit(0);
+ plugin_exit(0);
}
fflush(stdout);
+
+ netdata_mutex_unlock(&stdout_mutex);
}
}
diff --git a/collectors/freeipmi.plugin/integrations/intelligent_platform_management_interface_ipmi.md b/collectors/freeipmi.plugin/integrations/intelligent_platform_management_interface_ipmi.md
index 6d894667b..c0293fc37 100644
--- a/collectors/freeipmi.plugin/integrations/intelligent_platform_management_interface_ipmi.md
+++ b/collectors/freeipmi.plugin/integrations/intelligent_platform_management_interface_ipmi.md
@@ -4,6 +4,7 @@ meta_yaml: "https://github.com/netdata/netdata/edit/master/collectors/freeipmi.p
sidebar_label: "Intelligent Platform Management Interface (IPMI)"
learn_status: "Published"
learn_rel_path: "Data Collection/Hardware Devices and Sensors"
+most_popular: True
message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE COLLECTOR'S metadata.yaml FILE"
endmeta-->
@@ -170,30 +171,30 @@ To display a help message listing the available command line options:
| Name | Description | Default | Required |
|:----|:-----------|:-------|:--------:|
-| SECONDS | Data collection frequency. | | False |
-| debug | Enable verbose output. | disabled | False |
-| no-sel | Disable System Event Log (SEL) collection. | disabled | False |
-| reread-sdr-cache | Re-read SDR cache on every iteration. | disabled | False |
-| interpret-oem-data | Attempt to parse OEM data. | disabled | False |
-| assume-system-event-record | treat illegal SEL events records as normal. | disabled | False |
-| ignore-non-interpretable-sensors | Do not read sensors that cannot be interpreted. | disabled | False |
-| bridge-sensors | Bridge sensors not owned by the BMC. | disabled | False |
-| shared-sensors | Enable shared sensors if found. | disabled | False |
-| no-discrete-reading | Do not read sensors if their event/reading type code is invalid. | enabled | False |
-| ignore-scanning-disabled | Ignore the scanning bit and read sensors no matter what. | disabled | False |
-| assume-bmc-owner | Assume the BMC is the sensor owner no matter what (usually bridging is required too). | disabled | False |
-| hostname HOST | Remote IPMI hostname or IP address. | local | False |
-| username USER | Username that will be used when connecting to the remote host. | | False |
-| password PASS | Password that will be used when connecting to the remote host. | | False |
-| noauthcodecheck / no-auth-code-check | Don't check the authentication codes returned. | | False |
-| driver-type IPMIDRIVER | Specify the driver type to use instead of doing an auto selection. The currently available outofband drivers are LAN and LAN_2_0, which perform IPMI 1.5 and IPMI 2.0 respectively. The currently available inband drivers are KCS, SSIF, OPENIPMI and SUNBMC. | | False |
-| sdr-cache-dir PATH | SDR cache files directory. | /tmp | False |
-| sensor-config-file FILE | Sensors configuration filename. | system default | False |
-| sel-config-file FILE | SEL configuration filename. | system default | False |
-| ignore N1,N2,N3,... | Sensor IDs to ignore. | | False |
-| ignore-status N1,N2,N3,... | Sensor IDs to ignore status (nominal/warning/critical). | | False |
-| -v | Print version and exit. | | False |
-| --help | Print usage message and exit. | | False |
+| SECONDS | Data collection frequency. | | no |
+| debug | Enable verbose output. | disabled | no |
+| no-sel | Disable System Event Log (SEL) collection. | disabled | no |
+| reread-sdr-cache | Re-read SDR cache on every iteration. | disabled | no |
+| interpret-oem-data | Attempt to parse OEM data. | disabled | no |
+| assume-system-event-record | treat illegal SEL events records as normal. | disabled | no |
+| ignore-non-interpretable-sensors | Do not read sensors that cannot be interpreted. | disabled | no |
+| bridge-sensors | Bridge sensors not owned by the BMC. | disabled | no |
+| shared-sensors | Enable shared sensors if found. | disabled | no |
+| no-discrete-reading | Do not read sensors if their event/reading type code is invalid. | enabled | no |
+| ignore-scanning-disabled | Ignore the scanning bit and read sensors no matter what. | disabled | no |
+| assume-bmc-owner | Assume the BMC is the sensor owner no matter what (usually bridging is required too). | disabled | no |
+| hostname HOST | Remote IPMI hostname or IP address. | local | no |
+| username USER | Username that will be used when connecting to the remote host. | | no |
+| password PASS | Password that will be used when connecting to the remote host. | | no |
+| noauthcodecheck / no-auth-code-check | Don't check the authentication codes returned. | | no |
+| driver-type IPMIDRIVER | Specify the driver type to use instead of doing an auto selection. The currently available outofband drivers are LAN and LAN_2_0, which perform IPMI 1.5 and IPMI 2.0 respectively. The currently available inband drivers are KCS, SSIF, OPENIPMI and SUNBMC. | | no |
+| sdr-cache-dir PATH | SDR cache files directory. | /tmp | no |
+| sensor-config-file FILE | Sensors configuration filename. | system default | no |
+| sel-config-file FILE | SEL configuration filename. | system default | no |
+| ignore N1,N2,N3,... | Sensor IDs to ignore. | | no |
+| ignore-status N1,N2,N3,... | Sensor IDs to ignore status (nominal/warning/critical). | | no |
+| -v | Print version and exit. | | no |
+| --help | Print usage message and exit. | | no |
</details>