#define HAVE_VOLUME_USAGE_SNAP_USED 0x0080
#define HAVE_VOLUME_USAGE_SIS_SAVED 0x0100
#define HAVE_VOLUME_USAGE_ALL 0x01f0
+#define IS_VOLUME_USAGE_OFFLINE 0x0200
struct data_volume_usage_s;
typedef struct data_volume_usage_s data_volume_usage_t;
struct data_volume_usage_s {
data_volume_perf_t *old_data,
const data_volume_perf_t *new_data)
{
+ char plugin_instance[DATA_MAX_NAME_LEN];
+
+ if ((hostname == NULL) || (old_data == NULL) || (new_data == NULL))
+ return (-1);
+
+ ssnprintf (plugin_instance, sizeof (plugin_instance),
+ "volume-%s", old_data->name);
+
/* Check for and submit disk-octet values */
if (HAS_ALL_FLAGS (old_data->flags, CFG_VOLUME_PERF_IO)
&& HAS_ALL_FLAGS (new_data->flags, HAVE_VOLUME_PERF_BYTES_READ | HAVE_VOLUME_PERF_BYTES_WRITE))
{
- submit_two_counters (hostname, old_data->name, "disk_octets", /* type instance = */ NULL,
+ submit_two_counters (hostname, plugin_instance, "disk_octets", /* type instance = */ NULL,
(counter_t) new_data->read_bytes, (counter_t) new_data->write_bytes, new_data->timestamp);
}
if (HAS_ALL_FLAGS (old_data->flags, CFG_VOLUME_PERF_OPS)
&& HAS_ALL_FLAGS (new_data->flags, HAVE_VOLUME_PERF_OPS_READ | HAVE_VOLUME_PERF_OPS_WRITE))
{
- submit_two_counters (hostname, old_data->name, "disk_ops", /* type instance = */ NULL,
+ submit_two_counters (hostname, plugin_instance, "disk_ops", /* type instance = */ NULL,
(counter_t) new_data->read_ops, (counter_t) new_data->write_ops, new_data->timestamp);
}
latency_per_op_write = ((gauge_t) diff_latency_write) / ((gauge_t) diff_ops_write);
}
- submit_two_gauge (hostname, old_data->name, "disk_latency", /* type instance = */ NULL,
+ submit_two_gauge (hostname, plugin_instance, "disk_latency", /* type instance = */ NULL,
latency_per_op_read, latency_per_op_write, new_data->timestamp);
}
for (v = cfg_volume->volumes; v != NULL; v = v->next)
{
+ char plugin_instance[DATA_MAX_NAME_LEN];
+
uint64_t norm_used = v->norm_used;
uint64_t norm_free = v->norm_free;
uint64_t sis_saved = v->sis_saved;
uint64_t snap_reserve_free = v->snap_reserved;
uint64_t snap_norm_used = v->snap_used;
+ ssnprintf (plugin_instance, sizeof (plugin_instance),
+ "volume-%s", v->name);
+
if (HAS_ALL_FLAGS (v->flags, HAVE_VOLUME_USAGE_SNAP_USED | HAVE_VOLUME_USAGE_SNAP_RSVD)) {
if (v->snap_reserved > v->snap_used) {
snap_reserve_free = v->snap_reserved - v->snap_used;
snap_reserve_free = 0;
snap_reserve_used = v->snap_reserved;
snap_norm_used = v->snap_used - v->snap_reserved;
- if (HAS_ALL_FLAGS (v->flags, HAVE_VOLUME_USAGE_NORM_USED)
- && (norm_used >= snap_norm_used))
- norm_used -= snap_norm_used;
+ }
+ }
+
+ /* The space used by snapshots but not reserved for them is included in
+ * both, norm_used and snap_norm_used. If possible, subtract this here. */
+ if (HAS_ALL_FLAGS (v->flags, HAVE_VOLUME_USAGE_NORM_USED | HAVE_VOLUME_USAGE_SNAP_USED))
+ {
+ if (norm_used >= snap_norm_used)
+ norm_used -= snap_norm_used;
+ else
+ {
+ ERROR ("netapp plugin: (norm_used = %"PRIu64") < (snap_norm_used = "
+ "%"PRIu64"). Invalidating both.",
+ norm_used, snap_norm_used);
+ v->flags &= ~(HAVE_VOLUME_USAGE_NORM_USED | HAVE_VOLUME_USAGE_SNAP_USED);
}
}
if (HAS_ALL_FLAGS (v->flags, HAVE_VOLUME_USAGE_NORM_FREE))
- submit_double (hostname, /* plugin instance = */ v->name,
+ submit_double (hostname, /* plugin instance = */ plugin_instance,
"df_complex", "free",
(double) norm_free, /* timestamp = */ 0);
if (HAS_ALL_FLAGS (v->flags, HAVE_VOLUME_USAGE_SIS_SAVED))
- submit_double (hostname, /* plugin instance = */ v->name,
+ submit_double (hostname, /* plugin instance = */ plugin_instance,
"df_complex", "sis_saved",
(double) sis_saved, /* timestamp = */ 0);
if (HAS_ALL_FLAGS (v->flags, HAVE_VOLUME_USAGE_NORM_USED))
- submit_double (hostname, /* plugin instance = */ v->name,
+ submit_double (hostname, /* plugin instance = */ plugin_instance,
"df_complex", "used",
(double) norm_used, /* timestamp = */ 0);
if (HAS_ALL_FLAGS (v->flags, HAVE_VOLUME_USAGE_SNAP_RSVD))
- submit_double (hostname, /* plugin instance = */ v->name,
+ submit_double (hostname, /* plugin instance = */ plugin_instance,
"df_complex", "snap_reserved",
(double) snap_reserve_free, /* timestamp = */ 0);
if (HAS_ALL_FLAGS (v->flags, HAVE_VOLUME_USAGE_SNAP_USED | HAVE_VOLUME_USAGE_SNAP_RSVD))
- submit_double (hostname, /* plugin instance = */ v->name,
+ submit_double (hostname, /* plugin instance = */ plugin_instance,
"df_complex", "snap_reserve_used",
(double) snap_reserve_used, /* timestamp = */ 0);
if (HAS_ALL_FLAGS (v->flags, HAVE_VOLUME_USAGE_SNAP_USED))
- submit_double (hostname, /* plugin instance = */ v->name,
+ submit_double (hostname, /* plugin instance = */ plugin_instance,
"df_complex", "snap_normal_used",
(double) snap_norm_used, /* timestamp = */ 0);
return (0);
} /* }}} int cna_submit_volume_usage_data */
-static void cna_handle_volume_snap_usage(const host_config_t *host, data_volume_usage_t *v)
+/* Switch the state of a volume between online and offline and send out a
+ * notification. */
+static int cna_change_volume_status (const char *hostname, /* {{{ */
+ data_volume_usage_t *v)
+{
+ notification_t n;
+
+ memset (&n, 0, sizeof (&n));
+ n.time = time (NULL);
+ sstrncpy (n.host, hostname, sizeof (n.host));
+ sstrncpy (n.plugin, "netapp", sizeof (n.plugin));
+ sstrncpy (n.plugin_instance, v->name, sizeof (n.plugin_instance));
+
+ if ((v->flags & IS_VOLUME_USAGE_OFFLINE) != 0) {
+ n.severity = NOTIF_OKAY;
+ ssnprintf (n.message, sizeof (n.message),
+ "Volume %s is now online.", v->name);
+ v->flags &= ~IS_VOLUME_USAGE_OFFLINE;
+ } else {
+ n.severity = NOTIF_WARNING;
+ ssnprintf (n.message, sizeof (n.message),
+ "Volume %s is now offline.", v->name);
+ v->flags |= IS_VOLUME_USAGE_OFFLINE;
+ }
+
+ return (plugin_dispatch_notification (&n));
+} /* }}} int cna_change_volume_status */
+
+static void cna_handle_volume_snap_usage(const host_config_t *host, /* {{{ */
+ data_volume_usage_t *v)
{
uint64_t snap_used = 0, value;
na_elem_t *data, *elem_snap, *elem_snapshots;
data = na_server_invoke_elem(host->srv, v->snap_query);
if (na_results_status(data) != NA_OK)
{
- if (na_results_errno(data) != EVOLUMEOFFLINE)
+ if (na_results_errno(data) == EVOLUMEOFFLINE) {
+ if ((v->flags & IS_VOLUME_USAGE_OFFLINE) == 0)
+ cna_change_volume_status (host->name, v);
+ } else {
ERROR ("netapp plugin: cna_handle_volume_snap_usage: na_server_invoke_elem for "
"volume \"%s\" failed with error %d: %s", v->name,
na_results_errno(data), na_results_reason(data));
+ }
na_elem_free(data);
return;
}
+ if ((v->flags & IS_VOLUME_USAGE_OFFLINE) != 0)
+ cna_change_volume_status (host->name, v);
+
elem_snapshots = na_elem_child (data, "snapshots");
if (elem_snapshots == NULL)
{