Change in vdsm[master]: gluster: Get size information of a gluster volume.

dnarayan at redhat.com dnarayan at redhat.com
Wed Apr 2 05:17:27 UTC 2014


Darshan N has uploaded a new change for review.

Change subject: gluster: Get size information of a gluster volume.
......................................................................

gluster: Get size information of a gluster volume.

New vdsm gluster verb to get free, used and total size of
gluster volume. This verb uses gluster-libgfapi to get the
statistics related to volume.

verb: glusterVolumeStatsInfoGet

Output format:
{"sizeTotal": LONG as STR, "sizeFree": LONG as STR, "sizeUsed": LONG as STR}

Exception(s):
code:    4570
Name:    GlusterVolumeStatsInfoGetFailedException
Message: Failed to get Gluster volume <VOL NAME> Stats

code:    4571
Name:    GlusterVolumeIsNotOnlineException
Message: Failed to get Gluster volume stats

Change-Id: Ib628b10c3b9743bb9fef5cbf41195e69ff851efd
Signed-off-by: Darshan n <dnarayan at redhat.com>
---
M client/vdsClientGluster.py
M configure.ac
M vdsm.spec.in
M vdsm/Makefile.am
M vdsm/gluster/Makefile.am
M vdsm/gluster/__init__.py
M vdsm/gluster/api.py
M vdsm/gluster/exception.py
A vdsm/gluster/statvfs.py
M vdsm/gluster/vdsmapi-gluster-schema.json
A vdsm/gluster_glfs/Makefile.am
A vdsm/gluster_glfs/__init__.py
A vdsm/gluster_glfs/glfs_vol.h
A vdsm/gluster_glfs/setup.py
A vdsm/gluster_glfs/volCap.c
15 files changed, 313 insertions(+), 4 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/43/26343/1

diff --git a/client/vdsClientGluster.py b/client/vdsClientGluster.py
index 9fa58b2..421c853 100644
--- a/client/vdsClientGluster.py
+++ b/client/vdsClientGluster.py
@@ -422,6 +422,14 @@
         pp.pprint(status)
         return status['status']['code'], status['status']['message']
 
+    def do_glusterVolumeStatsInfoGet(self, args):
+        params = self._eqSplit(args)
+        volumeName = params.get('volumeName', '')
+
+        status = self.s.glusterVolumeStatsInfoGet(volumeName)
+        pp.pprint(status)
+        return status['status']['code'], status['status']['message']
+
 
 def getGlusterCmdDict(serv):
     return \
@@ -718,4 +726,9 @@
              ('[taskIds=<task_id1,task_id2,..>]',
               'list all or given gluster tasks'
               )),
+         'glusterVolumeStatsInfoGet': (
+             serv.do_glusterVolumeStatsInfoGet,
+             ('volumeName=<volume name>',
+              'Returns total, free and used space(bytes) of gluster volume'
+              )),
          }
diff --git a/configure.ac b/configure.ac
index 71f91bc..d260e4b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -270,6 +270,7 @@
 	vdsm-tool/Makefile
 	vdsm/Makefile
 	vdsm/gluster/Makefile
+	vdsm/gluster_glfs/Makefile
 	vdsm/netconf/Makefile
 	vdsm/sos/Makefile
 	vdsm/storage/Makefile
diff --git a/vdsm.spec.in b/vdsm.spec.in
index 6c92b15..77e563e 100644
--- a/vdsm.spec.in
+++ b/vdsm.spec.in
@@ -1,4 +1,3 @@
-# Packages names
 %global vdsm_name vdsm
 %global vdsm_bootstrap vdsm-bootstrap
 %global vdsm_reg vdsm-reg
@@ -61,6 +60,7 @@
 BuildRequires: python-nose
 BuildRequires: python-netaddr
 BuildRequires: rpm-build
+BuildRequires: glusterfs-devel
 
 # BuildRequires needed by the tests during the build
 BuildRequires: dosfstools
@@ -587,7 +587,6 @@
 %if 0%{?with_gluster}
 %package gluster
 Summary:        Gluster Plugin for VDSM
-BuildArch:      noarch
 
 Requires: %{name} = %{version}-%{release}
 Requires: glusterfs-server
@@ -629,6 +628,7 @@
 # Install the respawn utility
 install -Dm 0755 init/sysvinit/respawn \
                  %{buildroot}%{_datadir}/%{vdsm_name}/respawn
+
 
 # Install the lvm rules
 install -Dm 0644 vdsm/storage/vdsm-lvm.rules \
@@ -1431,12 +1431,22 @@
 %dir %{_datadir}/%{vdsm_name}/gluster
 %doc COPYING
 %{_datadir}/%{vdsm_name}/gluster/api.py*
+%{_datadir}/%{vdsm_name}/gluster/statvfs.py*
 %{_datadir}/%{vdsm_name}/gluster/vdsmapi-gluster-schema.json
 %{_datadir}/%{vdsm_name}/gluster/hooks.py*
 %{_datadir}/%{vdsm_name}/gluster/services.py*
 %{_datadir}/%{vdsm_name}/gluster/tasks.py*
 %endif
 
+%if 0%{?with_gluster}
+%defattr(-, root, root, -)
+%dir %{_datadir}/%{vdsm_name}/gluster_glfs
+%doc COPYING
+%{_datadir}/%{vdsm_name}/gluster_glfs/__init__.py*
+%{_datadir}/%{vdsm_name}/gluster_glfs/capacity.so*
+%endif
+
+
 %changelog
 * Sun Oct 13 2013 Yaniv Bronhaim <ybronhei at redhat.com> - 4.13.0
 - Removing vdsm-python-cpopen from the spec
diff --git a/vdsm/Makefile.am b/vdsm/Makefile.am
index 8ab0072..4e34936 100644
--- a/vdsm/Makefile.am
+++ b/vdsm/Makefile.am
@@ -18,7 +18,7 @@
 # Refer to the README and COPYING files for full details of the license
 #
 
-SUBDIRS = netconf sos storage gluster
+SUBDIRS = netconf sos storage gluster gluster_glfs
 
 include $(top_srcdir)/build-aux/Makefile.subs
 
diff --git a/vdsm/gluster/Makefile.am b/vdsm/gluster/Makefile.am
index b397e95..f30d67f 100644
--- a/vdsm/gluster/Makefile.am
+++ b/vdsm/gluster/Makefile.am
@@ -32,6 +32,7 @@
 	cli.py \
 	exception.py \
 	hooks.py \
+	statvfs.py \
 	services.py \
 	tasks.py \
 	$(NULL)
diff --git a/vdsm/gluster/__init__.py b/vdsm/gluster/__init__.py
index 0aefb8d..f86a5dc 100644
--- a/vdsm/gluster/__init__.py
+++ b/vdsm/gluster/__init__.py
@@ -22,7 +22,7 @@
 import tempfile
 from functools import wraps
 
-MODULE_LIST = ('cli', 'hooks', 'services', 'tasks')
+MODULE_LIST = ('cli', 'hooks', 'services', 'tasks', 'statvfs')
 
 
 def makePublic(func):
diff --git a/vdsm/gluster/api.py b/vdsm/gluster/api.py
index 761ee78..506cd10 100644
--- a/vdsm/gluster/api.py
+++ b/vdsm/gluster/api.py
@@ -306,6 +306,12 @@
         status = self.svdsmProxy.glusterTasksList(taskIds)
         return {'tasks': status}
 
+    @exportAsVerb
+    def volumeStatsInfoGet(self, volumeName, volumeServer='localhost',
+                           options=None):
+        return self.svdsmProxy.glusterVolumeStatsInfoGet(volumeName,
+                                                         volumeServer)
+
 
 def getGlusterMethods(gluster):
     l = []
diff --git a/vdsm/gluster/exception.py b/vdsm/gluster/exception.py
index 93a2225..1295ce4 100644
--- a/vdsm/gluster/exception.py
+++ b/vdsm/gluster/exception.py
@@ -486,3 +486,13 @@
         prefix = "%s: " % (action)
         self.message = prefix + "Service action is not supported"
         self.err = [self.message]
+
+
+class GlusterVolumeStatsInfoGetFailedException(GlusterException):
+    code = 4570
+    message = "Failed to get Gluster volume Stats"
+
+
+class GlusterVolumeIsNotOnlineException(GlusterVolumeException):
+    code = 4571
+    message = "Failed to get Gluster volume stats"
diff --git a/vdsm/gluster/statvfs.py b/vdsm/gluster/statvfs.py
new file mode 100644
index 0000000..af8ea92
--- /dev/null
+++ b/vdsm/gluster/statvfs.py
@@ -0,0 +1,60 @@
+#
+# Copyright 2013 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 logging
+from gluster_glfs.capacity import statvfs
+import exception as ge
+from . import makePublic
+from . import cli
+
+log = logging.getLogger("Gluster")
+
+
+ at makePublic
+def volumeStatsInfoGet(volumeName, volumeServer="localhost"):
+    volume_data = cli.volumeInfo(volumeName=volumeName,
+                                 remoteServer=volumeServer)
+    if volumeName not in volume_data:
+        msg = "Volume \"%s\" does not exists" % volumeName
+        raise ge.GlusterVolumeNameErrorException(err=[msg])
+
+    if volume_data[volumeName]['volumeStatus'] == cli.VolumeStatus.OFFLINE:
+        msg = "Volume \"%s\" is not Online" % volumeName
+        raise ge.GlusterVolumeIsNotOnlineException(err=[msg])
+
+    try:
+        statvfsData = statvfs(volumeName, volumeServer)
+    except:
+        errMsg = "Failed to retrive statistics"
+        " of glusterfs volume %s" % volumeName
+        raise ge.GlusterVolumeSizeInfoGetFailedException(err=[errMsg])
+
+    # f_blocks = Total number of blocks
+    # f_bfree = Total number of blocks free
+    # f_bavail = Total number of blocks available for non root user
+    # total blocks available = f_blocks - (f_bfree - f_bavail)
+    total = ((statvfsData['f_blocks'] -
+              (statvfsData['f_bfree'] - statvfsData['f_bavail'])) *
+             statvfsData['f_bsize'])
+    free = statvfsData['f_bavail'] * statvfsData['f_bsize']
+    used = total - free
+
+    return {'sizeTotal': str(total),
+            'sizeFree': str(free),
+            'sizeUsed': str(used)}
diff --git a/vdsm/gluster/vdsmapi-gluster-schema.json b/vdsm/gluster/vdsmapi-gluster-schema.json
index 4e80679..7c30c9e 100644
--- a/vdsm/gluster/vdsmapi-gluster-schema.json
+++ b/vdsm/gluster/vdsmapi-gluster-schema.json
@@ -1205,3 +1205,37 @@
 ##
 {'command': {'class': 'GlusterHost', 'name': 'list'},
  'returns': ['HostList']}
+
+##
+# @GlusterVolumeStatsInfo:
+#
+# Gluster Volumes disk usage statistics
+#
+# @sizeTotal: Total space available in bytes
+#
+# @sizeFree: Free space available in bytes
+#
+# @sizeUsed: Used space in bytes
+#
+# Since: 4.14.0
+##
+{'type': 'GlusterVolumeStatsInfo',
+ 'data': {'sizeTotal': 'str', 'sizeFree': 'str', 'sizeUsed': 'str'}}
+
+##
+# @GlusterVolume.statsInfoGet:
+#
+# Get the list of Gluster volumes
+#
+# @volumeName: Gluster volume name
+#
+# @volumeServer: Gluster volume server default is localhost
+#
+# Returns:
+# Stats info of GlusterFS volume
+#
+# Since: 4.14.0
+##
+{'command': {'class': 'GlusterVolume', 'name': 'statsInfoGet'},
+ 'data': {'volumeName': 'str', 'volumeServer': 'str'},
+ 'returns': 'GlusterVolumeStatsInfo'}
diff --git a/vdsm/gluster_glfs/Makefile.am b/vdsm/gluster_glfs/Makefile.am
new file mode 100644
index 0000000..f10158a
--- /dev/null
+++ b/vdsm/gluster_glfs/Makefile.am
@@ -0,0 +1,19 @@
+statisticsdir = $(vdsmdir)/gluster_glfs
+dist_statistics_PYTHON = \
+	__init__.py \
+	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 \
+	volCap.c \
+	setup.py
+CLEANFILES = \
+	volcap.o \
+	capacity.so
diff --git a/vdsm/gluster_glfs/__init__.py b/vdsm/gluster_glfs/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/vdsm/gluster_glfs/__init__.py
diff --git a/vdsm/gluster_glfs/glfs_vol.h b/vdsm/gluster_glfs/glfs_vol.h
new file mode 100644
index 0000000..80c8434
--- /dev/null
+++ b/vdsm/gluster_glfs/glfs_vol.h
@@ -0,0 +1,41 @@
+#include <syslog.h>
+
+#define GLFS_INIT_FAILURE -3 
+#define GLFS_FINI_FAILURE -5 
+#define DEFAULT_TRANSPORT "tcp" 
+#define DEFAULT_SERVER "127.0.0.1" 
+#define DEFAULT_SERVER_PORT 24007
+
+int get_volume (const char *volume_name, const char *server_name, glfs_t *fs)
+{
+  int ret = 0;
+  int rv = 0;
+  
+  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) 
+  {
+    syslog (LOG_ERR, "glfs_init() failed with code %d",ret);
+    rv = GLFS_INIT_FAILURE;
+    ret = glfs_fini (fs);
+    if (ret != 0)
+      {
+	syslog (LOG_ERR, "glfs_fini() failed with code %d\n", ret);
+      }
+
+    return rv;
+  }
+  sleep(3);
+  return 0;
+}
+
diff --git a/vdsm/gluster_glfs/setup.py b/vdsm/gluster_glfs/setup.py
new file mode 100644
index 0000000..e934817
--- /dev/null
+++ b/vdsm/gluster_glfs/setup.py
@@ -0,0 +1,11 @@
+from distutils.core import setup, Extension
+
+module1 = Extension('capacity', sources=['volCap.c'],
+                    libraries=['gfapi'])
+
+setup(name='capacity',
+      version='1.0',
+      description='gets volume capacity',
+      py_modules=['__init__'],
+      url='redhat.com',
+      ext_modules=[module1])
diff --git a/vdsm/gluster_glfs/volCap.c b/vdsm/gluster_glfs/volCap.c
new file mode 100644
index 0000000..bd3c646
--- /dev/null
+++ b/vdsm/gluster_glfs/volCap.c
@@ -0,0 +1,103 @@
+#include <Python.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/statvfs.h>
+#include "/usr/include/glusterfs/api/glfs.h"
+#include "/usr/include/glusterfs/api/glfs-handles.h"
+#include "glfs_vol.h"
+
+#define USAGE_ERROR -1 
+#define GLFS_NEW_FAILURE -2 
+#define GLFS_STATVFS_FAILURE -4 
+
+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)
+    {
+      syslog (LOG_ERR, "glfs_new: returned NULL");
+      return GLFS_NEW_FAILURE;
+    }
+  ret = get_volume(volume_name, server_name, fs);
+  if(ret!=0)
+    { 
+      return ret;
+    }
+  ret = glfs_statvfs (fs, "/", &statvfsinfo);
+  if (ret == 0)
+  {
+    *buf = statvfsinfo;
+  }
+  else
+  {
+    syslog (LOG_ERR, "glfs_statvfs() failed with [%d:%s] for \"/\"\n", ret, strerror (errno));
+    rv = GLFS_STATVFS_FAILURE;
+  }
+  ret = glfs_fini (fs);
+  if (ret != 0)
+  {
+    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;
+
+  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 ();
+  if(rv==0)
+  return Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i}","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 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.");
+}


-- 
To view, visit http://gerrit.ovirt.org/26343
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ib628b10c3b9743bb9fef5cbf41195e69ff851efd
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Darshan N <dnarayan at redhat.com>


More information about the vdsm-patches mailing list