From e0bdeafae88282506ceb23b948354ccba658e7af Mon Sep 17 00:00:00 2001 From: Ramesh Nachimuthu Date: Tue, 17 Jun 2014 16:26:20 +0530 Subject: nagios-addons: Using ctypes to call gfapi Removing the volCap.c which was used to call libgfapi and calling libgfapi directly from python using ctypes. Change-Id: Ia78f212c769c34e5cb991e429623946a4256e2af Signed-off-by: Ramesh Nachimuthu Reviewed-on: http://review.gluster.org/8090 Reviewed-by: Sahina Bose Reviewed-by: Bala FA --- plugins/Makefile.am | 5 +- plugins/check_vol_utilization.py | 43 ++++++----- plugins/gfapi.py | 161 +++++++++++++++++++++++++++++++++++++++ plugins/volcap/Makefile.am | 20 ----- plugins/volcap/__init__.py | 0 plugins/volcap/setup.py | 11 --- plugins/volcap/tests.py | 0 plugins/volcap/volCap.c | 143 ---------------------------------- 8 files changed, 187 insertions(+), 196 deletions(-) create mode 100644 plugins/gfapi.py delete mode 100644 plugins/volcap/Makefile.am delete mode 100644 plugins/volcap/__init__.py delete mode 100644 plugins/volcap/setup.py delete mode 100644 plugins/volcap/tests.py delete mode 100644 plugins/volcap/volCap.c diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 417b312..47ff64d 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -1,7 +1,3 @@ -SUBDIRS = \ - volcap \ - $(NULL) - initdir = $(sysconfdir)/init.d init_DATA = \ glusterpmd \ @@ -26,6 +22,7 @@ dist_glusternagiosplugins_PYTHON = \ check_gluster_proc_status.py \ check_proc_util.py \ __init__.py \ + gfapi.py \ memory.py \ network.py \ nscautils.py \ diff --git a/plugins/check_vol_utilization.py b/plugins/check_vol_utilization.py index 2593ca7..d909c9b 100755 --- a/plugins/check_vol_utilization.py +++ b/plugins/check_vol_utilization.py @@ -19,32 +19,39 @@ import sys import argparse -import capacity from glusternagios import utils from glusternagios import glustercli +import gfapi + + +BYTES_IN_KB = 1024 + + +def computeVolumeStats(data): + total = data.f_blocks * data.f_bsize + free = data.f_bfree * data.f_bsize + used = total - free + return {'sizeTotal': float(total), + 'sizeFree': float(free), + 'sizeUsed': float(used)} def showVolumeUtilization(vname, warnLevel, critLevel): - buf = {} try: - buf = capacity.statvfs(vname, "localhost") - except Exception: - sys.stdout.write("UNKNOWN: Failed to get the " + data = gfapi.getVolumeStatvfs(vname) + except gfapi.GlusterLibgfapiException: + sys.stdout.write("CRITICAL: Failed to get the " "Volume Utilization Data\n") - sys.exit(utils.PluginStatusCode.UNKNOWN) -#################################################################### -# statvfs.frsize * statvfs.f_blocks# Size of filesystem in bytes # -# statvfs.frsize * statvfs.f_bfree # Actual number of free bytes # -# statvfs.frsize * statvfs.f_bavail# Number of free bytes that # -# ordinary users are allowed to use (excl. reserved space # -#################################################################### - # total size in KB - total_size = (buf['f_bsize'] * buf['f_blocks']) / 1024.0 - # Available free size in KB - free_size = (buf['f_bsize'] * buf['f_bavail']) / 1024.0 - # used size in KB - used_size = total_size - ((buf['f_bsize'] * buf['f_bfree']) / 1024.0) + sys.exit(utils.PluginStatusCode.CRITICAL) + volumeCapacity = computeVolumeStats(data) + #total size in KB + total_size = volumeCapacity['sizeTotal'] / BYTES_IN_KB + #Available free size in KB + free_size = volumeCapacity['sizeFree'] / BYTES_IN_KB + #used size in KB + used_size = volumeCapacity['sizeUsed'] / BYTES_IN_KB vol_utilization = (used_size / total_size) * 100 + perfLines = [] perfLines.append(("utilization=%.2f%%;%d;%d total=%0.2f " "used=%0.2f free=%0.2f" % (vol_utilization, warnLevel, diff --git a/plugins/gfapi.py b/plugins/gfapi.py new file mode 100644 index 0000000..4df3531 --- /dev/null +++ b/plugins/gfapi.py @@ -0,0 +1,161 @@ +# +# Copyright 2014 Red Hat, Inc. +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# +# Refer to the README and COPYING files for full details of the license +# +import ctypes +from ctypes.util import find_library +import os + + +GLUSTER_VOL_PROTOCAL = 'tcp' +GLUSTER_VOL_HOST = 'localhost' +GLUSTER_VOL_PORT = 24007 +GLUSTER_VOL_PATH = "/" + + +class GlusterLibgfapiException(Exception): + message = "Gluster Libgfapi Exception" + + def __init__(self, rc=0, err=()): + self.rc = rc + self.err = err + + def __str__(self): + s = self.message + if self.err: + e = '\n'.join(self.err) + s += '\nerror: ' + e + if self.rc: + s += '\nreturn code: %s' % self.rc + return s + + +class GlfsStatvfsException(GlusterLibgfapiException): + message = "Failed to get Gluster volume Size info" + + +class GlfsInitException(GlusterLibgfapiException): + message = "glfs init failed" + + +class GlfsFiniException(GlusterLibgfapiException): + message = "glfs fini failed" + + +class StatVfsStruct(ctypes.Structure): + _fields_ = [ + ('f_bsize', ctypes.c_ulong), + ('f_frsize', ctypes.c_ulong), + ('f_blocks', ctypes.c_ulong), + ('f_bfree', ctypes.c_ulong), + ('f_bavail', ctypes.c_ulong), + ('f_files', ctypes.c_ulong), + ('f_ffree', ctypes.c_ulong), + ('f_favail', ctypes.c_ulong), + ('f_fsid', ctypes.c_ulong), + ('f_flag', ctypes.c_ulong), + ('f_namemax', ctypes.c_ulong), + ('__f_spare', ctypes.c_int * 6), + ] + + +def glfsInit(volumeId, host, port, protocol): + fs = _glfs_new(volumeId) + + rc = _glfs_set_volfile_server(fs, + protocol, + host, + port) + if rc != 0: + raise GlfsInitException( + rc=rc, err=["setting volfile server failed"] + ) + + rc = _glfs_init(fs) + if rc == 0: + return fs + elif rc == 1: + raise GlfsInitException( + rc=rc, err=["Volume:%s is stopped." % volumeId] + ) + elif rc == -1: + raise GlfsInitException( + rc=rc, err=["Volume:%s not found." % volumeId] + ) + else: + raise GlfsInitException(rc=rc, err=["unknown error."]) + + +def glfsFini(fs, volumeId): + rc = _glfs_fini(fs) + if rc != 0: + raise GlfsFiniException(rc=rc) + + +def getVolumeStatvfs(volumeId, host=GLUSTER_VOL_HOST, + port=GLUSTER_VOL_PORT, + protocol=GLUSTER_VOL_PROTOCAL): + statvfsdata = StatVfsStruct() + + fs = glfsInit(volumeId, host, port, protocol) + + rc = _glfs_statvfs(fs, GLUSTER_VOL_PATH, ctypes.byref(statvfsdata)) + if rc != 0: + raise GlfsStatvfsException(rc=rc) + + glfsFini(fs, volumeId) + + # To convert to os.statvfs_result we need to pass tuple/list in + # following order: bsize, frsize, blocks, bfree, bavail, files, + # ffree, favail, flag, namemax + return os.statvfs_result((statvfsdata.f_bsize, + statvfsdata.f_frsize, + statvfsdata.f_blocks, + statvfsdata.f_bfree, + statvfsdata.f_bavail, + statvfsdata.f_files, + statvfsdata.f_ffree, + statvfsdata.f_favail, + statvfsdata.f_flag, + statvfsdata.f_namemax)) + +# C function prototypes for using the library gfapi + +_lib = ctypes.CDLL(find_library("gfapi"), + use_errno=True) + +_glfs_new = ctypes.CFUNCTYPE( + ctypes.c_void_p, ctypes.c_char_p)(('glfs_new', _lib)) + +_glfs_set_volfile_server = ctypes.CFUNCTYPE( + ctypes.c_int, + ctypes.c_void_p, + ctypes.c_char_p, + ctypes.c_char_p, + ctypes.c_int)(('glfs_set_volfile_server', _lib)) + +_glfs_init = ctypes.CFUNCTYPE( + ctypes.c_int, ctypes.c_void_p)(('glfs_init', _lib)) + +_glfs_fini = ctypes.CFUNCTYPE( + ctypes.c_int, ctypes.c_void_p)(('glfs_fini', _lib)) + +_glfs_statvfs = ctypes.CFUNCTYPE(ctypes.c_int, + ctypes.c_void_p, + ctypes.c_char_p, + ctypes.c_void_p)(('glfs_statvfs', _lib)) diff --git a/plugins/volcap/Makefile.am b/plugins/volcap/Makefile.am deleted file mode 100644 index 1c4e5c6..0000000 --- a/plugins/volcap/Makefile.am +++ /dev/null @@ -1,20 +0,0 @@ - -nodist_glusternagiosplugins_PYTHON = \ - capacity.so \ - $(NULL) - -capacity.so: volCap.c setup.py - (cd $(srcdir); $(PYTHON) setup.py build \ - --build-temp $(abs_builddir) --build-lib $(abs_builddir)) -all-local: capacity.so - -EXTRA_DIST = \ - __init__.py \ - setup.py \ - tests.py \ - volCap.c \ - $(NULL) - -CLEANFILES = \ - volcap.o \ - capacity.so diff --git a/plugins/volcap/__init__.py b/plugins/volcap/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/plugins/volcap/setup.py b/plugins/volcap/setup.py deleted file mode 100644 index b37e090..0000000 --- a/plugins/volcap/setup.py +++ /dev/null @@ -1,11 +0,0 @@ -from distutils.core import setup, Extension - -module1 = Extension('capacity', - sources=['volCap.c'], libraries=['gfapi']) - -setup(name='capacity', - version='1.0', - description='Gets the volume capcity Utilization', - py_modules=['__init__'], - url='redhat.com', - ext_modules=[module1]) diff --git a/plugins/volcap/tests.py b/plugins/volcap/tests.py deleted file mode 100644 index e69de29..0000000 diff --git a/plugins/volcap/volCap.c b/plugins/volcap/volCap.c deleted file mode 100644 index 8c0c4e4..0000000 --- a/plugins/volcap/volCap.c +++ /dev/null @@ -1,143 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include "/usr/include/glusterfs/api/glfs.h" -#include "/usr/include/glusterfs/api/glfs-handles.h" -#include - -#define USAGE_ERROR -1 -#define GLFS_NEW_FAILURE -2 -#define GLFS_INIT_FAILURE -3 -#define GLFS_STATVFS_FAILURE -4 -#define GLFS_FINI_FAILURE -5 -#define DEFAULT_TRANSPORT "tcp" -#define DEFAULT_SERVER "127.0.0.1" -#define DEFAULT_SERVER_PORT 24007 - -static PyObject *StatvfsError; - -int get_volume_statvfs (const char *volume_name, const char *server_name, struct statvfs *buf) -{ - glfs_t *fs = NULL; - int ret = 0; - struct statvfs statvfsinfo = {0, }; - int rv = 0; - - if (!(volume_name && buf)) - { - return USAGE_ERROR; - } - - fs = glfs_new (volume_name); - if (!fs) - { - //fprintf (stderr, "glfs_new: returned NULL\n"); - syslog (LOG_ERR, "glfs_new: returned NULL"); - return GLFS_NEW_FAILURE; - } - - if (server_name) - { - ret = glfs_set_volfile_server(fs, DEFAULT_TRANSPORT, server_name, DEFAULT_SERVER_PORT); - } - else - { - ret = glfs_set_volfile_server(fs, DEFAULT_TRANSPORT, DEFAULT_SERVER, DEFAULT_SERVER_PORT); - } - - ret = glfs_set_logging (fs, "/tmp/libg.txt", 2); - - ret = glfs_init (fs); - if (ret != 0) - { - //fprintf (stderr, "glfs_init() failed with code %d\n", ret); - syslog (LOG_ERR, "glfs_init() failed with code %d",ret); - rv = GLFS_INIT_FAILURE; - goto out; - } - - /*fprintf (stdout, "waiting for 3 seconds to initialize\n");*/ - sleep (3); - - ret = glfs_statvfs (fs, "/", &statvfsinfo); - if (ret == 0) - { - *buf = statvfsinfo; - } - else - { - //fprintf (stderr, "glfs_statvfs() failed with [%d:%s] for \"/\"\n", ret, strerror (errno)); - syslog (LOG_ERR, "glfs_statvfs() failed with [%d:%s] for \"/\"\n", ret, strerror (errno)); - rv = GLFS_STATVFS_FAILURE; - } - - out: - ret = glfs_fini (fs); - if (ret != 0) - { - //fprintf (stderr, "glfs_fini() failed with code %d\n", ret); - syslog (LOG_ERR, "glfs_fini() failed with code %d\n", ret); - } - - return rv; -} - -static PyObject *glfspy_statvfs (PyObject *self, PyObject *args) -{ - char *volume_name = NULL; - char *server_name = NULL; - int port = 0; - char *transport = NULL; - struct statvfs buf = {0, }; - int rv = 0; -#define USAGE_ERROR -1 -#define GLFS_NEW_FAILURE -2 -#define GLFS_INIT_FAILURE -3 -#define GLFS_STATVFS_FAILURE -4 -#define GLFS_FINI_FAILURE -5 - - StatvfsError = PyErr_NewException("statvfs.error", NULL, NULL); - setlogmask (LOG_UPTO (LOG_DEBUG)); - openlog ("statvfs", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1); - syslog (LOG_INFO, "Invoking glfspy_statvfs to get the volume utlization"); - if (!PyArg_ParseTuple (args, "s|ziz", &volume_name, &server_name, &port, &transport)) - { - PyErr_SetString(StatvfsError, "Argument parsing failed"); - return NULL; - } - - rv = get_volume_statvfs (volume_name, server_name, &buf); - closelog (); - //return Py_BuildValue("i", rv); - if(rv == 0) - return Py_BuildValue("{s:l,s:l,s:l,s:l,s:l,s:l,s:l,s:l,s:l,s:l,s:l}","f_bsize",buf.f_bsize,"f_frsize",buf.f_frsize,"f_blocks",buf.f_blocks,"f_bfree",buf.f_bfree,"f_bavail",buf.f_bavail,"f_files",buf.f_files,"f_ffree",buf.f_ffree,"f_favail",buf.f_favail,"f_fsid",buf.f_fsid,"f_flag",buf.f_flag,"f_namemax",buf.f_namemax); - else { - if(rv == USAGE_ERROR) - PyErr_SetString(StatvfsError, "Usage error"); - if(rv == GLFS_NEW_FAILURE) - PyErr_SetString(StatvfsError, "glfs_new() failed"); - if(rv == GLFS_INIT_FAILURE) - PyErr_SetString(StatvfsError, "glfs_init() failed"); - if(rv == GLFS_STATVFS_FAILURE) - PyErr_SetString(StatvfsError, "glfs_statvfs() failed"); - //return Py_BuildValue("i", rv); - return NULL; - } -} - - -static PyMethodDef glfspy_methods[] = { - { "statvfs", (PyCFunction)glfspy_statvfs, METH_VARARGS, NULL }, - { NULL, NULL, 0, NULL } -}; - - -PyMODINIT_FUNC initcapacity () -{ - Py_InitModule3 ("capacity", glfspy_methods, "gluster gfapi top level extension module."); -} -- cgit