Discussion:
[DEMO 2/2] Demo: simple test for C and python API on sd-2-vpd.
Gris Ge
2015-10-29 05:54:58 UTC
Permalink
Usage:

Python:
lsmenv sim ./test/test_vpd.py 600508b1001c79ade5178f0626caaa9c
or if you prefer the install way:
./test/test_vpd.py 600508b1001c79ade5178f0626caaa9c

C:
make test/test_vpd83 && test/test_vpd83 600508b1001c79ade5178f0626caaa9c

Signed-off-by: Gris Ge <***@redhat.com>
---
test/Makefile.am | 5 +++++
test/test_vpd83.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
test/test_vpd83.py | 10 ++++++++++
3 files changed, 63 insertions(+)
create mode 100644 test/test_vpd83.c
create mode 100755 test/test_vpd83.py

diff --git a/test/Makefile.am b/test/Makefile.am
index 872e8e0..4b591e4 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -11,3 +11,8 @@ check_PROGRAMS = tester
tester_CFLAGS = $(LIBCHECK_CFLAGS)
tester_LDADD = ../c_binding/libstoragemgmt.la $(LIBCHECK_LIBS)
tester_SOURCES = tester.c
+
+bin_PROGRAMS = test_vpd83
+test_vpd83_CFLAGS = $(LIBCHECK_CFLAGS)
+test_vpd83_LDADD = ../c_binding/libstoragemgmt.la $(LIBCHECK_LIBS)
+test_vpd83_SOURCES = test_vpd83.c
diff --git a/test/test_vpd83.c b/test/test_vpd83.c
new file mode 100644
index 0000000..aa22dc3
--- /dev/null
+++ b/test/test_vpd83.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <***@redhat.com>
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <libstoragemgmt/libstoragemgmt.h>
+
+int main(int argc, char **argv)
+{
+ const char **sd_names= NULL;
+ uint32_t sd_name_count = 0;
+ uint32_t i = 0;
+ int rc = 0;
+
+ if (argc != 2) {
+ printf("Please only define a VPD83 in command line\n");
+ exit(EXIT_FAILURE);
+ }
+
+ rc = lsm_scsi_disk_name_list_of_vpd83(argv[1], &sd_names, &sd_name_count);
+
+ if (sd_names != NULL) {
+ for(; i < sd_name_count; ++i) {
+ printf("got %s\n", sd_names[i]);
+ }
+ lsm_scsi_disk_name_list_free(sd_names, sd_name_count);
+ exit(EXIT_SUCCESS);
+ }
+ printf("not found, error: %d\n", rc);
+ exit(EXIT_FAILURE);
+}
diff --git a/test/test_vpd83.py b/test/test_vpd83.py
new file mode 100755
index 0000000..914d76f
--- /dev/null
+++ b/test/test_vpd83.py
@@ -0,0 +1,10 @@
+#!/usr/bin/python2
+
+import lsm
+import sys
+
+if len(sys.argv) != 2:
+ print "Please specify 1 VPD83 ID"
+ exit()
+
+print lsm.SCSI.disk_name_of_vpd83(sys.argv[1])
--
1.8.3.1
Gris Ge
2015-11-03 14:19:14 UTC
Permalink
* API for querying scsi disk names from VPD83 ID.
C:
int lsm_scsi_disk_names_of_vpd83(const char *vpd83,
lsm_string_list **sd_name_list)

Python:
lsm.SCSI.disk_names_of_vpd83(vpd83)

* lsmcli changes: add "Disk Names", example:

lsmcli lv -s
--------------------------------
ID | VOL_ID_00001
Name | lsm_RDIQVLWJYZKK
SCSI VPD 0x83 | 53333330000007d0
Block Size | 512
Block Count | 61440
Size | 31457280
Disabled | No
Pool ID | POOL_ID_00004
System ID | sim-01
Disk Names | sdb
| sdd
| sdf
| sdh
--------------------------------

Github pull request is:
https://github.com/libstorage/libstoragemgmt/pull/71

Gris Ge (8):
C API: New function for SCSI disk name matching.
Python API: New function for SCSI disk name matching.
lsmcli: Add SCSI disk names in output of volume listing.
C unit test: Test case for lsm_scsi_disk_names_of_vpd83()
RPM SPEC: Add new python library file.
Constant check: Support python absolute import.
lsmcli test: Fix failed test case caused by new disk name colume.
lsmcli test: Fix test case volume_raid_create_test()

c_binding/Makefile.am | 8 +-
c_binding/include/libstoragemgmt/Makefile.am | 1 +
c_binding/include/libstoragemgmt/libstoragemgmt.h | 1 +
.../include/libstoragemgmt/libstoragemgmt_scsi.h | 49 +++++++
c_binding/lsm_scsi.c | 147 +++++++++++++++++++++
configure.ac | 2 +
packaging/libstoragemgmt.spec.in | 1 +
python_binding/Makefile.am | 1 +
python_binding/lsm/__init__.py | 2 +
python_binding/lsm/_scsi.py | 53 ++++++++
test/cmdtest.py | 5 +-
test/tester.c | 37 ++++++
tools/lsmcli/cmdline.py | 35 +++--
tools/lsmcli/data_display.py | 1 +
tools/utility/check_const.pl | 9 +-
15 files changed, 334 insertions(+), 18 deletions(-)
create mode 100644 c_binding/include/libstoragemgmt/libstoragemgmt_scsi.h
create mode 100644 c_binding/lsm_scsi.c
create mode 100644 python_binding/lsm/_scsi.py

--
1.8.3.1
Gris Ge
2015-11-03 14:19:15 UTC
Permalink
* New method lsm_scsi_disk_names_of_vpd83() takes VPD83 ID to find out
all matching scsi disk names(format:sdX).

Signed-off-by: Gris Ge <***@redhat.com>
---
c_binding/Makefile.am | 8 +-
c_binding/include/libstoragemgmt/Makefile.am | 1 +
c_binding/include/libstoragemgmt/libstoragemgmt.h | 1 +
.../include/libstoragemgmt/libstoragemgmt_scsi.h | 49 +++++++
c_binding/lsm_scsi.c | 147 +++++++++++++++++++++
configure.ac | 2 +
6 files changed, 205 insertions(+), 3 deletions(-)
create mode 100644 c_binding/include/libstoragemgmt/libstoragemgmt_scsi.h
create mode 100644 c_binding/lsm_scsi.c

diff --git a/c_binding/Makefile.am b/c_binding/Makefile.am
index e4b8e1b..18da493 100644
--- a/c_binding/Makefile.am
+++ b/c_binding/Makefile.am
@@ -3,13 +3,15 @@ SUBDIRS = include
AM_CPPFLAGS = -I$(top_srcdir)/c_binding/include \
-I$(top_builddir)/c_binding/include \
-***@srcdir@/c_binding/include \
- $(LIBXML_CFLAGS) $(LIBGLIB_CFLAGS)
+ $(LIBXML_CFLAGS) $(LIBGLIB_CFLAGS) \
+ $(LIBUDEV_CFLAGS)

lib_LTLIBRARIES = libstoragemgmt.la

-libstoragemgmt_la_LIBADD=$(LIBXML_LIBS) $(YAJL_LIBS) $(LIBGLIB_LIBS)
+libstoragemgmt_la_LIBADD=$(LIBXML_LIBS) $(YAJL_LIBS) $(LIBGLIB_LIBS) \
+ $(LIBUDEV_LIBS)
libstoragemgmt_la_LDFLAGS= -version-info $(LIBSM_LIBTOOL_VERSION)
libstoragemgmt_la_SOURCES= \
lsm_mgmt.cpp lsm_datatypes.hpp lsm_datatypes.cpp lsm_convert.hpp \
lsm_convert.cpp lsm_ipc.hpp lsm_ipc.cpp lsm_plugin_ipc.hpp \
- lsm_plugin_ipc.cpp util/qparams.c util/qparams.h
+ lsm_plugin_ipc.cpp util/qparams.c util/qparams.h lsm_scsi.c
diff --git a/c_binding/include/libstoragemgmt/Makefile.am b/c_binding/include/libstoragemgmt/Makefile.am
index 2a947f6..f7b8dbd 100644
--- a/c_binding/include/libstoragemgmt/Makefile.am
+++ b/c_binding/include/libstoragemgmt/Makefile.am
@@ -23,6 +23,7 @@ lsminc_HEADERS = \
libstoragemgmt_targetport.h \
libstoragemgmt_types.h \
libstoragemgmt_version.h \
+ libstoragemgmt_scsi.h \
libstoragemgmt_volumes.h


diff --git a/c_binding/include/libstoragemgmt/libstoragemgmt.h b/c_binding/include/libstoragemgmt/libstoragemgmt.h
index b902bd8..8450434 100644
--- a/c_binding/include/libstoragemgmt/libstoragemgmt.h
+++ b/c_binding/include/libstoragemgmt/libstoragemgmt.h
@@ -34,6 +34,7 @@
#include "libstoragemgmt_systems.h"
#include "libstoragemgmt_targetport.h"
#include "libstoragemgmt_volumes.h"
+#include "libstoragemgmt_scsi.h"


/*! \mainpage libStorageMgmt
diff --git a/c_binding/include/libstoragemgmt/libstoragemgmt_scsi.h b/c_binding/include/libstoragemgmt/libstoragemgmt_scsi.h
new file mode 100644
index 0000000..fe77b8c
--- /dev/null
+++ b/c_binding/include/libstoragemgmt/libstoragemgmt_scsi.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <***@redhat.com>
+ *
+ */
+
+#ifndef LIBSTORAGEMGMT_SCSI_H
+#define LIBSTORAGEMGMT_SCSI_H
+
+#include "libstoragemgmt_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Find out the scsi disk names of given SCSI VPD page 0x83 NAA ID.
+ * New in version 1.3.
+ * @param[in] vpd83 String. The VPD83 ID retrieved from LSM volume or disk.
+ * for supported strip sizes.
+ * @param[out] sd_name_list.
+ * Output pointer of lsm_string_list.
+ * NULL if no found or got error.
+ * Memory should be freed by lsm_string_list_free().
+ * @return LSM_ERR_OK on success
+ * LSM_ERR_INVALID_ARGUMENT when vpd83 or sd_name pointer is NULL
+ * LSM_ERR_NO_MEMORY when no memory
+ * LSM_ERR_LIB_BUG when something unexpected happens
+ */
+int LSM_DLL_EXPORT lsm_scsi_disk_names_of_vpd83(const char *vpd83,
+ lsm_string_list **sd_name_list);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* LIBSTORAGEMGMT_SCSI_H */
diff --git a/c_binding/lsm_scsi.c b/c_binding/lsm_scsi.c
new file mode 100644
index 0000000..78a5fa3
--- /dev/null
+++ b/c_binding/lsm_scsi.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <***@redhat.com>
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <libudev.h>
+
+#include "libstoragemgmt/libstoragemgmt.h"
+#include "libstoragemgmt/libstoragemgmt_error.h"
+
+/*
+ * Using ID_WWN_WITH_EXTENSION udev property to match given VPD83.
+ * TODO(Gris Ge): Try to use /sys/block/sda/device/vpd_pg83 file as
+ * failback way or even replace current udev way if performance
+ * is good.
+ *
+ */
+int lsm_scsi_disk_names_of_vpd83(const char *vpd83,
+ lsm_string_list **sd_name_list)
+
+{
+ struct udev *udev = NULL;
+ struct udev_enumerate *enumerate_sd = NULL;
+ struct udev_list_entry *sd_udevices = NULL;
+ struct udev_list_entry *sd_udev_list = NULL;
+ struct udev_list_entry *sd_udev_list_entry = NULL;
+ struct udev_device *sd_udev = NULL;
+ const char *sd_udev_path = NULL;
+ const char *sd_path = NULL;
+ char *wwn = NULL;
+ int rc = LSM_ERR_OK;
+ const char *dev_type = NULL;
+
+ if ((vpd83 == NULL) || (sd_name_list == NULL))
+ return LSM_ERR_INVALID_ARGUMENT;
+
+ wwn = (char *) malloc(sizeof(char) *
+ (strlen(vpd83) + strlen("0x") + 1 /* tailing \0 */));
+
+ if (wwn == NULL) {
+ rc = LSM_ERR_NO_MEMORY;
+ goto out;
+ }
+
+ sprintf(wwn, "0x%s", vpd83);
+
+ udev = udev_new();
+ if (udev == NULL) {
+ rc = LSM_ERR_NO_MEMORY;
+ goto out;
+ }
+
+ enumerate_sd = udev_enumerate_new(udev);
+ if (enumerate_sd == NULL) {
+ rc = LSM_ERR_NO_MEMORY;
+ goto out;
+ }
+
+ if (udev_enumerate_add_match_subsystem(enumerate_sd, "block") != 0) {
+ rc = LSM_ERR_LIB_BUG;
+ goto out;
+ }
+
+ if (udev_enumerate_add_match_property(enumerate_sd, "ID_WWN_WITH_EXTENSION",
+ wwn) != 0) {
+ rc = LSM_ERR_LIB_BUG;
+ goto out;
+ }
+
+ if (udev_enumerate_scan_devices(enumerate_sd) != 0) {
+ rc = LSM_ERR_LIB_BUG;
+ goto out;
+ }
+
+ *sd_name_list = lsm_string_list_alloc(0 /* No pre-allocation */);
+ if (*sd_name_list == NULL) {
+ rc = LSM_ERR_NO_MEMORY;
+ goto out;
+ }
+ sd_udevices = udev_enumerate_get_list_entry(enumerate_sd);
+ udev_list_entry_foreach(sd_udev_list_entry, sd_udevices) {
+ sd_udev_path = udev_list_entry_get_name(sd_udev_list_entry);
+ if (sd_udev_path == NULL)
+ continue;
+
+ sd_udev = udev_device_new_from_syspath(udev, sd_udev_path);
+ if (sd_udev == NULL) {
+ rc = LSM_ERR_LIB_BUG;
+ goto out;
+ }
+
+ dev_type = udev_device_get_property_value(sd_udev, "DEVTYPE");
+ if ((dev_type == NULL) || (strcmp(dev_type, "disk") != 0)) {
+ udev_device_unref(sd_udev);
+ continue;
+ }
+
+ sd_path = udev_device_get_devnode(sd_udev);
+ if ((sd_path == NULL) ||
+ (strncmp(sd_path, "/dev/sd", strlen("/dev/sd")) != 0)) {
+ udev_device_unref(sd_udev);
+ continue;
+ }
+ if (lsm_string_list_append(*sd_name_list,
+ sd_path + strlen("/dev/")) != 0) {
+ rc = LSM_ERR_NO_MEMORY;
+ goto out;
+ }
+ }
+
+ out:
+ if (udev != NULL) {
+ udev_unref(udev);
+ }
+ if (enumerate_sd != NULL) {
+ udev_enumerate_unref(enumerate_sd);
+ }
+
+ if (wwn != NULL)
+ free(wwn);
+
+ if (*sd_name_list != NULL) {
+ if ((rc != LSM_ERR_OK) || (lsm_string_list_size(*sd_name_list) == 0)) {
+ lsm_string_list_free(*sd_name_list);
+ *sd_name_list = NULL;
+ }
+ }
+
+ return rc;
+}
diff --git a/configure.ac b/configure.ac
index beae390..53acb41 100644
--- a/configure.ac
+++ b/configure.ac
@@ -162,6 +162,8 @@ AM_PATH_PYTHON([2.6], [], AC_MSG_ERROR([Python interpreter 2.6 or 2.7 required])
AC_PYTHON_MODULE([pywbem], [Required])
AC_PYTHON_MODULE([M2Crypto], [Required])
AC_PYTHON_MODULE([argparse], [Required])
+AC_PYTHON_MODULE([pyudev], [Required])
+PKG_CHECK_MODULES([LIBUDEV], [libudev])

dnl ==========================================================================
dnl Check for libmicrohttpd and json-c as it is needed for REST API daemon
--
1.8.3.1
Gris Ge
2015-11-03 14:19:16 UTC
Permalink
* New function lsm.SCSI.disk_names_of_vpd83() to search all matching
SCSI disks(format: sdx) for given VPD83 ID.

Signed-off-by: Gris Ge <***@redhat.com>
---
python_binding/Makefile.am | 1 +
python_binding/lsm/__init__.py | 2 ++
python_binding/lsm/_scsi.py | 53 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 56 insertions(+)
create mode 100644 python_binding/lsm/_scsi.py

diff --git a/python_binding/Makefile.am b/python_binding/Makefile.am
index 8b0581a..0fe1a6d 100644
--- a/python_binding/Makefile.am
+++ b/python_binding/Makefile.am
@@ -10,6 +10,7 @@ lsm_PYTHON = \
lsm/_transport.py \
lsm/version.py \
lsm/_iplugin.py \
+ lsm/_scsi.py \
lsm/_pluginrunner.py

external_PYTHON = \
diff --git a/python_binding/lsm/__init__.py b/python_binding/lsm/__init__.py
index fb1cdbd..eb3a10e 100644
--- a/python_binding/lsm/__init__.py
+++ b/python_binding/lsm/__init__.py
@@ -2,6 +2,8 @@

from version import VERSION

+from lsm._scsi import SCSI
+
from _common import error, info, LsmError, ErrorNumber, \
JobStatus, uri_parse, md5, Proxy, size_bytes_2_size_human, \
common_urllib2_error_handler, size_human_2_size_bytes
diff --git a/python_binding/lsm/_scsi.py b/python_binding/lsm/_scsi.py
new file mode 100644
index 0000000..3d06a45
--- /dev/null
+++ b/python_binding/lsm/_scsi.py
@@ -0,0 +1,53 @@
+# Copyright (C) 2015 Red Hat, Inc.
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Gris Ge <***@redhat.com>
+
+## TODO(Gris Ge): Try to use use C API lsm_scsi_disk_name_list_of_vpd83()
+## instead of duplicate udev call here:
+## https://docs.python.org/2/extending/extending.html
+
+import pyudev
+
+class SCSI(object):
+ @staticmethod
+ def disk_names_of_vpd83(vpd83):
+ """
+ Version:
+ 1.3
+ Usage:
+ Find out the sdX name for given SCSI VPD page 0x83 NAA type ID.
+ Parameters:
+ vpd83 (string)
+ The VPD83 NAA type ID.
+ Returns:
+ sd_name (list of string)
+ Empty list is not found. The string format is 'sdz'.
+
+ SpecialExceptions:
+ N/A
+ Capability:
+ N/A
+ No capability required from plugin as this is a library level
+ method.
+ """
+ rc = []
+ context = pyudev.Context()
+ wwn = '0x%s' % vpd83
+ for dev in context.list_devices(subsystem='block',
+ ID_WWN_WITH_EXTENSION=wwn):
+ sd_path = str(dev.device_node)
+ if sd_path.startswith("/dev/sd") and dev['DEVTYPE'] == "disk":
+ rc.append(sd_path[len("/dev/"):])
+ return rc
--
1.8.3.1
Gris Ge
2015-11-03 14:19:17 UTC
Permalink
* The `lsmcli list --type volumes` will include local scsi disks if VPD83
matches. Example:

$ lsmcli lv -s
--------------------------------
ID | VOL_ID_00001
Name | test
SCSI VPD 0x83 | 53333330000007d0
Block Size | 512
Block Count | 2097152
Size | 1073741824
Disabled | No
Pool ID | POOL_ID_00001
System ID | sim-01
Disk Names | sdb
| sdd
| sdf
| sdh
--------------------------------

Signed-off-by: Gris Ge <***@redhat.com>
---
tools/lsmcli/cmdline.py | 35 +++++++++++++++++++++++------------
tools/lsmcli/data_display.py | 1 +
2 files changed, 24 insertions(+), 12 deletions(-)

diff --git a/tools/lsmcli/cmdline.py b/tools/lsmcli/cmdline.py
index c66eaf2..563abe1 100644
--- a/tools/lsmcli/cmdline.py
+++ b/tools/lsmcli/cmdline.py
@@ -34,7 +34,7 @@
from lsm import (Client, Pool, VERSION, LsmError, Disk,
Volume, JobStatus, ErrorNumber, BlockRange,
uri_parse, Proxy, size_human_2_size_bytes,
- AccessGroup, FileSystem, NfsExport, TargetPort)
+ AccessGroup, FileSystem, NfsExport, TargetPort, SCSI)

from lsm.lsmcli.data_display import (
DisplayData, PlugData, out,
@@ -904,20 +904,24 @@ def list(self, args):
search_value = args.tgt

if args.type == 'VOLUMES':
+ lsm_vols = []
if search_key == 'volume_id':
search_key = 'id'
if search_key == 'access_group_id':
lsm_ag = _get_item(self.c.access_groups(), args.ag,
"Access Group", raise_error=False)
if lsm_ag:
- return self.display_data(
- self.c.volumes_accessible_by_access_group(lsm_ag))
- else:
- return self.display_data([])
+ lsm_vols = self.c.volumes_accessible_by_access_group(
+ lsm_ag)
elif search_key and search_key not in Volume.SUPPORTED_SEARCH_KEYS:
raise ArgError("Search key '%s' is not supported by "
"volume listing." % search_key)
- self.display_data(self.c.volumes(search_key, search_value))
+ else:
+ lsm_vols = self.c.volumes(search_key, search_value)
+
+ self.display_data(
+ list(self._vol_add_sd_names(v) for v in lsm_vols))
+
elif args.type == 'POOLS':
if search_key == 'pool_id':
search_key = 'id'
@@ -1023,7 +1027,7 @@ def access_group_volumes(self, args):
agl = self.c.access_groups()
group = _get_item(agl, args.ag, "Access Group")
vols = self.c.volumes_accessible_by_access_group(group)
- self.display_data(vols)
+ self.display_data(list(self._vol_add_sd_names(v) for v in vols))

def iscsi_chap(self, args):
(init_id, init_type) = parse_convert_init(args.init)
@@ -1163,7 +1167,7 @@ def volume_create(self, args):
args.name,
self._size(args.size),
vol_provision_str_to_type(args.provisioning)))
- self.display_data([vol])
+ self.display_data([self._vol_add_sd_names(vol)])

## Creates a snapshot
def fs_snap_create(self, args):
@@ -1271,7 +1275,7 @@ def volume_replicate(self, args):
vol = self._wait_for_it(
"replicate volume",
*self.c.volume_replicate(p, rep_type, v, args.name))
- self.display_data([vol])
+ self.display_data([self._vol_add_sd_names(vol)])

## Replicates a range of a volume
def volume_replicate_range(self, args):
@@ -1324,7 +1328,7 @@ def volume_resize(self, args):
if self.confirm_prompt(False):
vol = self._wait_for_it("resize",
*self.c.volume_resize(v, size))
- self.display_data([vol])
+ self.display_data([self._vol_add_sd_names(vol)])

## Enable a volume
def volume_enable(self, args):
@@ -1413,8 +1417,9 @@ def volume_raid_create(self, args):
strip_size = Volume.VCR_STRIP_SIZE_DEFAULT

self.display_data([
- self.c.volume_raid_create(
- args.name, raid_type, lsm_disks, strip_size)])
+ self._vol_add_sd_names(
+ self.c.volume_raid_create(
+ args.name, raid_type, lsm_disks, strip_size))])

def volume_raid_create_cap(self, args):
lsm_sys = _get_item(self.c.systems(), args.sys, "System")
@@ -1536,3 +1541,9 @@ def process(self, cli=None):

self.args.func(self.args)
self.shutdown()
+
+ def _vol_add_sd_names(self, lsm_vol):
+ lsm_vol.sd_names = []
+ if len(lsm_vol.vpd83) > 0:
+ lsm_vol.sd_names = SCSI.disk_names_of_vpd83(lsm_vol.vpd83)
+ return lsm_vol
diff --git a/tools/lsmcli/data_display.py b/tools/lsmcli/data_display.py
index 2feda46..9318580 100644
--- a/tools/lsmcli/data_display.py
+++ b/tools/lsmcli/data_display.py
@@ -418,6 +418,7 @@ def __init__(self):
VOL_HEADER['admin_state'] = 'Disabled'
VOL_HEADER['pool_id'] = 'Pool ID'
VOL_HEADER['system_id'] = 'System ID'
+ VOL_HEADER['sd_names'] = 'Disk Names' # This is appended by cmdline.py

VOL_COLUMN_SKIP_KEYS = ['block_size', 'num_of_blocks']
--
1.8.3.1
Gris Ge
2015-11-03 14:19:18 UTC
Permalink
* Simply test LSM_ERR_INVALID_ARGUMENT of lsm_scsi_disk_names_of_vpd83().

Signed-off-by: Gris Ge <***@redhat.com>
---
test/tester.c | 37 +++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)

diff --git a/test/tester.c b/test/tester.c
index da2a3a4..357e7c4 100644
--- a/test/tester.c
+++ b/test/tester.c
@@ -36,6 +36,7 @@ const char *ISCSI_HOST[2] = { "iqn.1994-05.com.domain:01.89bd01",
static int which_plugin = 0;

#define POLL_SLEEP 50000
+#define VPD83_TO_SEARCH "600508b1001c79ade5178f0626caaa9c"

lsm_connect *c = NULL;

@@ -3083,6 +3084,42 @@ START_TEST(test_volume_raid_create)
}
END_TEST

+
+/*
+ * Just check whether LSM_ERR_INVALID_ARGUMENT handle correctly.
+ */
+START_TEST(test_scsi_disk_names_of_vpd83)
+{
+ int rc;
+ lsm_string_list *sd_name_list = NULL;
+
+ if (which_plugin == 1){
+ /* silently skip on simc, no need for duplicate test. */
+ return;
+ }
+ rc = lsm_scsi_disk_names_of_vpd83(NULL, &sd_name_list);
+ fail_unless(
+ rc == LSM_ERR_INVALID_ARGUMENT,
+ "lsm_scsi_disk_names_of_vpd83(): Expecting LSM_ERR_INVALID_ARGUMENT "
+ "when vpd83 argument pointer is NULL");
+
+ rc = lsm_scsi_disk_names_of_vpd83(VPD83_TO_SEARCH, NULL);
+ fail_unless(
+ rc == LSM_ERR_INVALID_ARGUMENT,
+ "lsm_scsi_disk_names_of_vpd83(): Expecting LSM_ERR_INVALID_ARGUMENT "
+ "when sd_name_list argument pointer is NULL");
+
+ rc = lsm_scsi_disk_names_of_vpd83(VPD83_TO_SEARCH, &sd_name_list);
+ fail_unless(
+ rc == LSM_ERR_OK,
+ "lsm_scsi_disk_names_of_vpd83(): Expecting LSM_ERR_OK"
+ "when no argument is NULL");
+ if (sd_name_list != NULL)
+ lsm_string_list_free(sd_name_list);
+}
+END_TEST
+
+
Suite * lsm_suite(void)
{
Suite *s = suite_create("libStorageMgmt");
--
1.8.3.1
Gris Ge
2015-11-03 14:19:19 UTC
Permalink
* Add the new python_binding/lsm/_scsi.py file.

Signed-off-by: Gris Ge <***@redhat.com>
---
packaging/libstoragemgmt.spec.in | 1 +
1 file changed, 1 insertion(+)

diff --git a/packaging/libstoragemgmt.spec.in b/packaging/libstoragemgmt.spec.in
index 00da8c8..f109dfa 100644
--- a/packaging/libstoragemgmt.spec.in
+++ b/packaging/libstoragemgmt.spec.in
@@ -540,6 +540,7 @@ fi
%{python_sitelib}/lsm/external/*
%{python_sitelib}/lsm/_client.*
%{python_sitelib}/lsm/_common.*
+%{python_sitelib}/lsm/_scsi.*
%{python_sitelib}/lsm/_data.*
%{python_sitelib}/lsm/_iplugin.*
%{python_sitelib}/lsm/_pluginrunner.*
--
1.8.3.1
Gris Ge
2015-11-03 14:19:20 UTC
Permalink
* Just allow python absolute import like:
from lsm._scsi import SCSI

Signed-off-by: Gris Ge <***@redhat.com>
---
tools/utility/check_const.pl | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/tools/utility/check_const.pl b/tools/utility/check_const.pl
index 64abf34..2b2eead 100644
--- a/tools/utility/check_const.pl
+++ b/tools/utility/check_const.pl
@@ -267,7 +267,14 @@ sub _parse_py_init_file($) {

foreach my $line (@lines) {
if ( $line =~ /from ([^ ]+) import (.+)$/ ) {
- push @rc1, sprintf "%s/%s.py", $folder_path, $1;
+ my $module_file_name = $1;
+ if ($module_file_name =~ /^lsm\.(.+)$/) {
+ $module_file_name = $1;
+ $module_file_name =~ s|\.|/|g;
+ push @rc1, sprintf "%s/%s.py", $folder_path, $module_file_name;
+ } else {
+ push @rc1, sprintf "%s/%s.py", $folder_path, $module_file_name;
+ }
my $class_line = $2;
while ( $class_line =~ /([A-Z][a-zA-Z]+)[, \\]*/g ) {
push @rc2, $1;
--
1.8.3.1
Gris Ge
2015-11-03 14:19:21 UTC
Permalink
* New "Disk Name" column added to volume listing, which cause list[-2]
does not pointing to pool id, changed it to index number 5.

Signed-off-by: Gris Ge <***@redhat.com>
---
test/cmdtest.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/cmdtest.py b/test/cmdtest.py
index 7fa6599..bbf39a4 100755
--- a/test/cmdtest.py
+++ b/test/cmdtest.py
@@ -750,7 +750,7 @@ def volume_raid_create_test(cap, system_id):

volume = parse(out)
vol_id = volume[0][0]
- pool_id = volume[0][-2]
+ pool_id = volume[0][5]

if cap['VOLUME_RAID_INFO']:
out = call(
--
1.8.3.1
Gris Ge
2015-11-03 14:19:22 UTC
Permalink
* Use random generated volume name for volume_raid_create_test() test.

Signed-off-by: Gris Ge <***@redhat.com>
---
test/cmdtest.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/test/cmdtest.py b/test/cmdtest.py
index bbf39a4..22ee372 100755
--- a/test/cmdtest.py
+++ b/test/cmdtest.py
@@ -745,7 +745,8 @@ def volume_raid_create_test(cap, system_id):

out = call([
cmd, '-t' + sep, 'volume-raid-create', '--disk', free_disk_ids[0],
- '--disk', free_disk_ids[1], '--name', 'test_volume_raid_create',
+ '--disk', free_disk_ids[1], '--name',
+ 'test_volume_raid_create_%s' % rs(4),
'--raid-type', 'raid1'])[1]

volume = parse(out)
--
1.8.3.1
Tom Coughlan
2015-11-03 21:26:46 UTC
Permalink
Post by Gris Ge
d83(vpd83)
...
Post by Gris Ge
Disk Names | sdb
| sdd
| sdf
| sdh
Kind of a nit, but I wonder whether "Path Names" would be better.

The "sd name" is an alias for the h:c:t:l. This might be a good place to
re-enforce the idea.

Just a thought (I may very well not have all that necessary lsmcli
context).

Tom
Gris Ge
2015-11-04 03:44:39 UTC
Permalink
Post by Tom Coughlan
Post by Gris Ge
d83(vpd83)
...
Post by Gris Ge
Disk Names | sdb
| sdd
| sdf
| sdh
Kind of a nit, but I wonder whether "Path Names" would be better.
The "sd name" is an alias for the h:c:t:l. This might be a good
place to re-enforce the idea.
Just a thought (I may very well not have all that necessary lsmcli
context).
Tom
Hi Tom,

Thanks for pointing this out.

If I read the Linux kernel correctly, the kernel is using
"scsi disk name" term for sdX:
/drivers/scsi/sd.c sd_format_disk_name() has these comments:

SCSI disk names starts at sda. The 26th device is sdz and
the 27th is sdaa. The last one for two lettered suffix is
sdzz which is followed by sdaaa.

So I assume, "sdX" is SCSI disk name and "/dev/sdX" is path name.

We do have discussion about whether use path name or disk name in
github pull request page:
https://github.com/libstorage/libstoragemgmt/pull/71

Best regards.
--
Gris Ge
Tom Coughlan
2015-11-04 16:07:15 UTC
Permalink
Post by Gris Ge
Post by Tom Coughlan
Post by Gris Ge
d83(vpd83)
...
Post by Gris Ge
Disk Names | sdb
| sdd
| sdf
| sdh
Kind of a nit, but I wonder whether "Path Names" would be better.
The "sd name" is an alias for the h:c:t:l. This might be a good
place to re-enforce the idea.
Just a thought (I may very well not have all that necessary lsmcli
context).
Tom
Hi Tom,
Thanks for pointing this out.
If I read the Linux kernel correctly, the kernel is using
SCSI disk names starts at sda. The 26th device is sdz and
the 27th is sdaa. The last one for two lettered suffix is
sdzz which is followed by sdaaa.
It is likely that comment was written before they decided to implement
multipath above the "sd" device, not below.

Regardless, it is often necessary to adjust the nomenclature in the
kernel code for end-user consumption.
Post by Gris Ge
So I assume, "sdX" is SCSI disk name and "/dev/sdX" is path name.
The path name I am referring to is the physical I/O path (h:c:t:l), not
the filename path. So I don't think the above distinction helps.
Post by Gris Ge
We do have discussion about whether use path name or disk name in
https://github.com/libstorage/libstoragemgmt/pull/71
Thanks.

Tom
Gris Ge
2015-11-09 05:49:03 UTC
Permalink
* API for querying scsi disk names from VPD83 ID.
C:
int lsm_scsi_disk_names_of_vpd83(const char *vpd83,
lsm_string_list **sd_name_list)

Python:
lsm.SCSI.disk_names_of_vpd83(vpd83)

* lsmcli changes: add "Disk Names", example:

lsmcli lv -s
--------------------------------
ID | VOL_ID_00001
Name | lsm_RDIQVLWJYZKK
SCSI VPD 0x83 | 53333330000007d0
Block Size | 512
Block Count | 61440
Size | 31457280
Disabled | No
Pool ID | POOL_ID_00004
System ID | sim-01
Disk Names | sdb
| sdd
| sdf
| sdh
--------------------------------

Github pull request is:
https://github.com/libstorage/libstoragemgmt/pull/71

Changes in V2:

* API name changed to lsm_scsi_disk_paths_of_vpd83() and
lsm.SCSI.disk_paths_of_vpd83().
* Fixed dangling pointer of sd_path_list.
* Add test for dangling pointer of sd_path_list.
* Changed lsmcli output name as Disk Paths.


Gris Ge (9):
C API: New function for SCSI disk path matching.
Python API: New function for SCSI disk path matching.
lsmcli: Add SCSI disk paths in output of volume listing.
C unit test: Test case for lsm_scsi_disk_paths_of_vpd83()
RPM SPEC: Add new python library file.
Constant check: Support python absolute import.
lsmcli test: Fix failed test case caused by new disk name colume.
lsmcli test: Fix test case volume_raid_create_test()
Travis CI: Add new compile dependency.

.travis.yml | 2 +
c_binding/Makefile.am | 8 +-
c_binding/include/libstoragemgmt/Makefile.am | 1 +
c_binding/include/libstoragemgmt/libstoragemgmt.h | 1 +
.../include/libstoragemgmt/libstoragemgmt_scsi.h | 50 +++++++
c_binding/lsm_scsi.c | 147 +++++++++++++++++++++
configure.ac | 2 +
packaging/libstoragemgmt.spec.in | 1 +
python_binding/Makefile.am | 1 +
python_binding/lsm/__init__.py | 2 +
python_binding/lsm/_scsi.py | 55 ++++++++
test/cmdtest.py | 5 +-
test/tester.c | 42 ++++++
tools/lsmcli/cmdline.py | 35 +++--
tools/lsmcli/data_display.py | 1 +
tools/utility/check_const.pl | 9 +-
16 files changed, 344 insertions(+), 18 deletions(-)
create mode 100644 c_binding/include/libstoragemgmt/libstoragemgmt_scsi.h
create mode 100644 c_binding/lsm_scsi.c
create mode 100644 python_binding/lsm/_scsi.py
--
1.8.3.1
Gris Ge
2015-11-09 05:49:04 UTC
Permalink
* New method lsm_scsi_disk_names_of_vpd83() takes VPD83 ID to find out
all matching scsi disk names(format:sdX).

Signed-off-by: Gris Ge <***@redhat.com>
---
c_binding/Makefile.am | 8 +-
c_binding/include/libstoragemgmt/Makefile.am | 1 +
c_binding/include/libstoragemgmt/libstoragemgmt.h | 1 +
.../include/libstoragemgmt/libstoragemgmt_scsi.h | 49 +++++++
c_binding/lsm_scsi.c | 147 +++++++++++++++++++++
configure.ac | 2 +
6 files changed, 205 insertions(+), 3 deletions(-)
create mode 100644 c_binding/include/libstoragemgmt/libstoragemgmt_scsi.h
create mode 100644 c_binding/lsm_scsi.c

diff --git a/c_binding/Makefile.am b/c_binding/Makefile.am
index e4b8e1b..18da493 100644
--- a/c_binding/Makefile.am
+++ b/c_binding/Makefile.am
@@ -3,13 +3,15 @@ SUBDIRS = include
AM_CPPFLAGS = -I$(top_srcdir)/c_binding/include \
-I$(top_builddir)/c_binding/include \
-***@srcdir@/c_binding/include \
- $(LIBXML_CFLAGS) $(LIBGLIB_CFLAGS)
+ $(LIBXML_CFLAGS) $(LIBGLIB_CFLAGS) \
+ $(LIBUDEV_CFLAGS)

lib_LTLIBRARIES = libstoragemgmt.la

-libstoragemgmt_la_LIBADD=$(LIBXML_LIBS) $(YAJL_LIBS) $(LIBGLIB_LIBS)
+libstoragemgmt_la_LIBADD=$(LIBXML_LIBS) $(YAJL_LIBS) $(LIBGLIB_LIBS) \
+ $(LIBUDEV_LIBS)
libstoragemgmt_la_LDFLAGS= -version-info $(LIBSM_LIBTOOL_VERSION)
libstoragemgmt_la_SOURCES= \
lsm_mgmt.cpp lsm_datatypes.hpp lsm_datatypes.cpp lsm_convert.hpp \
lsm_convert.cpp lsm_ipc.hpp lsm_ipc.cpp lsm_plugin_ipc.hpp \
- lsm_plugin_ipc.cpp util/qparams.c util/qparams.h
+ lsm_plugin_ipc.cpp util/qparams.c util/qparams.h lsm_scsi.c
diff --git a/c_binding/include/libstoragemgmt/Makefile.am b/c_binding/include/libstoragemgmt/Makefile.am
index 2a947f6..f7b8dbd 100644
--- a/c_binding/include/libstoragemgmt/Makefile.am
+++ b/c_binding/include/libstoragemgmt/Makefile.am
@@ -23,6 +23,7 @@ lsminc_HEADERS = \
libstoragemgmt_targetport.h \
libstoragemgmt_types.h \
libstoragemgmt_version.h \
+ libstoragemgmt_scsi.h \
libstoragemgmt_volumes.h


diff --git a/c_binding/include/libstoragemgmt/libstoragemgmt.h b/c_binding/include/libstoragemgmt/libstoragemgmt.h
index b902bd8..8450434 100644
--- a/c_binding/include/libstoragemgmt/libstoragemgmt.h
+++ b/c_binding/include/libstoragemgmt/libstoragemgmt.h
@@ -34,6 +34,7 @@
#include "libstoragemgmt_systems.h"
#include "libstoragemgmt_targetport.h"
#include "libstoragemgmt_volumes.h"
+#include "libstoragemgmt_scsi.h"


/*! \mainpage libStorageMgmt
diff --git a/c_binding/include/libstoragemgmt/libstoragemgmt_scsi.h b/c_binding/include/libstoragemgmt/libstoragemgmt_scsi.h
new file mode 100644
index 0000000..fe77b8c
--- /dev/null
+++ b/c_binding/include/libstoragemgmt/libstoragemgmt_scsi.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <***@redhat.com>
+ *
+ */
+
+#ifndef LIBSTORAGEMGMT_SCSI_H
+#define LIBSTORAGEMGMT_SCSI_H
+
+#include "libstoragemgmt_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Find out the scsi disk names of given SCSI VPD page 0x83 NAA ID.
+ * New in version 1.3.
+ * @param[in] vpd83 String. The VPD83 ID retrieved from LSM volume or disk.
+ * for supported strip sizes.
+ * @param[out] sd_name_list.
+ * Output pointer of lsm_string_list.
+ * NULL if no found or got error.
+ * Memory should be freed by lsm_string_list_free().
+ * @return LSM_ERR_OK on success
+ * LSM_ERR_INVALID_ARGUMENT when vpd83 or sd_name pointer is NULL
+ * LSM_ERR_NO_MEMORY when no memory
+ * LSM_ERR_LIB_BUG when something unexpected happens
+ */
+int LSM_DLL_EXPORT lsm_scsi_disk_names_of_vpd83(const char *vpd83,
+ lsm_string_list **sd_name_list);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* LIBSTORAGEMGMT_SCSI_H */
diff --git a/c_binding/lsm_scsi.c b/c_binding/lsm_scsi.c
new file mode 100644
index 0000000..78a5fa3
--- /dev/null
+++ b/c_binding/lsm_scsi.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <***@redhat.com>
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <libudev.h>
+
+#include "libstoragemgmt/libstoragemgmt.h"
+#include "libstoragemgmt/libstoragemgmt_error.h"
+
+/*
+ * Using ID_WWN_WITH_EXTENSION udev property to match given VPD83.
+ * TODO(Gris Ge): Try to use /sys/block/sda/device/vpd_pg83 file as
+ * failback way or even replace current udev way if performance
+ * is good.
+ *
+ */
+int lsm_scsi_disk_names_of_vpd83(const char *vpd83,
+ lsm_string_list **sd_name_list)
+
+{
+ struct udev *udev = NULL;
+ struct udev_enumerate *enumerate_sd = NULL;
+ struct udev_list_entry *sd_udevices = NULL;
+ struct udev_list_entry *sd_udev_list = NULL;
+ struct udev_list_entry *sd_udev_list_entry = NULL;
+ struct udev_device *sd_udev = NULL;
+ const char *sd_udev_path = NULL;
+ const char *sd_path = NULL;
+ char *wwn = NULL;
+ int rc = LSM_ERR_OK;
+ const char *dev_type = NULL;
+
+ if ((vpd83 == NULL) || (sd_name_list == NULL))
+ return LSM_ERR_INVALID_ARGUMENT;
+
+ wwn = (char *) malloc(sizeof(char) *
+ (strlen(vpd83) + strlen("0x") + 1 /* tailing \0 */));
+
+ if (wwn == NULL) {
+ rc = LSM_ERR_NO_MEMORY;
+ goto out;
+ }
+
+ sprintf(wwn, "0x%s", vpd83);
+
+ udev = udev_new();
+ if (udev == NULL) {
+ rc = LSM_ERR_NO_MEMORY;
+ goto out;
+ }
+
+ enumerate_sd = udev_enumerate_new(udev);
+ if (enumerate_sd == NULL) {
+ rc = LSM_ERR_NO_MEMORY;
+ goto out;
+ }
+
+ if (udev_enumerate_add_match_subsystem(enumerate_sd, "block") != 0) {
+ rc = LSM_ERR_LIB_BUG;
+ goto out;
+ }
+
+ if (udev_enumerate_add_match_property(enumerate_sd, "ID_WWN_WITH_EXTENSION",
+ wwn) != 0) {
+ rc = LSM_ERR_LIB_BUG;
+ goto out;
+ }
+
+ if (udev_enumerate_scan_devices(enumerate_sd) != 0) {
+ rc = LSM_ERR_LIB_BUG;
+ goto out;
+ }
+
+ *sd_name_list = lsm_string_list_alloc(0 /* No pre-allocation */);
+ if (*sd_name_list == NULL) {
+ rc = LSM_ERR_NO_MEMORY;
+ goto out;
+ }
+ sd_udevices = udev_enumerate_get_list_entry(enumerate_sd);
+ udev_list_entry_foreach(sd_udev_list_entry, sd_udevices) {
+ sd_udev_path = udev_list_entry_get_name(sd_udev_list_entry);
+ if (sd_udev_path == NULL)
+ continue;
+
+ sd_udev = udev_device_new_from_syspath(udev, sd_udev_path);
+ if (sd_udev == NULL) {
+ rc = LSM_ERR_LIB_BUG;
+ goto out;
+ }
+
+ dev_type = udev_device_get_property_value(sd_udev, "DEVTYPE");
+ if ((dev_type == NULL) || (strcmp(dev_type, "disk") != 0)) {
+ udev_device_unref(sd_udev);
+ continue;
+ }
+
+ sd_path = udev_device_get_devnode(sd_udev);
+ if ((sd_path == NULL) ||
+ (strncmp(sd_path, "/dev/sd", strlen("/dev/sd")) != 0)) {
+ udev_device_unref(sd_udev);
+ continue;
+ }
+ if (lsm_string_list_append(*sd_name_list,
+ sd_path + strlen("/dev/")) != 0) {
+ rc = LSM_ERR_NO_MEMORY;
+ goto out;
+ }
+ }
+
+ out:
+ if (udev != NULL) {
+ udev_unref(udev);
+ }
+ if (enumerate_sd != NULL) {
+ udev_enumerate_unref(enumerate_sd);
+ }
+
+ if (wwn != NULL)
+ free(wwn);
+
+ if (*sd_name_list != NULL) {
+ if ((rc != LSM_ERR_OK) || (lsm_string_list_size(*sd_name_list) == 0)) {
+ lsm_string_list_free(*sd_name_list);
+ *sd_name_list = NULL;
+ }
+ }
+
+ return rc;
+}
diff --git a/configure.ac b/configure.ac
index beae390..53acb41 100644
--- a/configure.ac
+++ b/configure.ac
@@ -162,6 +162,8 @@ AM_PATH_PYTHON([2.6], [], AC_MSG_ERROR([Python interpreter 2.6 or 2.7 required])
AC_PYTHON_MODULE([pywbem], [Required])
AC_PYTHON_MODULE([M2Crypto], [Required])
AC_PYTHON_MODULE([argparse], [Required])
+AC_PYTHON_MODULE([pyudev], [Required])
+PKG_CHECK_MODULES([LIBUDEV], [libudev])

dnl ==========================================================================
dnl Check for libmicrohttpd and json-c as it is needed for REST API daemon
--
1.8.3.1
Gris Ge
2015-11-09 05:49:05 UTC
Permalink
* New method lsm_scsi_disk_paths_of_vpd83() takes VPD83 ID to find out
all matching scsi disk paths(format:/dev/sd[a-z]+).

Signed-off-by: Gris Ge <***@redhat.com>
---
c_binding/Makefile.am | 8 +-
c_binding/include/libstoragemgmt/Makefile.am | 1 +
c_binding/include/libstoragemgmt/libstoragemgmt.h | 1 +
.../include/libstoragemgmt/libstoragemgmt_scsi.h | 50 +++++++
c_binding/lsm_scsi.c | 147 +++++++++++++++++++++
configure.ac | 2 +
6 files changed, 206 insertions(+), 3 deletions(-)
create mode 100644 c_binding/include/libstoragemgmt/libstoragemgmt_scsi.h
create mode 100644 c_binding/lsm_scsi.c

diff --git a/c_binding/Makefile.am b/c_binding/Makefile.am
index e4b8e1b..18da493 100644
--- a/c_binding/Makefile.am
+++ b/c_binding/Makefile.am
@@ -3,13 +3,15 @@ SUBDIRS = include
AM_CPPFLAGS = -I$(top_srcdir)/c_binding/include \
-I$(top_builddir)/c_binding/include \
-***@srcdir@/c_binding/include \
- $(LIBXML_CFLAGS) $(LIBGLIB_CFLAGS)
+ $(LIBXML_CFLAGS) $(LIBGLIB_CFLAGS) \
+ $(LIBUDEV_CFLAGS)

lib_LTLIBRARIES = libstoragemgmt.la

-libstoragemgmt_la_LIBADD=$(LIBXML_LIBS) $(YAJL_LIBS) $(LIBGLIB_LIBS)
+libstoragemgmt_la_LIBADD=$(LIBXML_LIBS) $(YAJL_LIBS) $(LIBGLIB_LIBS) \
+ $(LIBUDEV_LIBS)
libstoragemgmt_la_LDFLAGS= -version-info $(LIBSM_LIBTOOL_VERSION)
libstoragemgmt_la_SOURCES= \
lsm_mgmt.cpp lsm_datatypes.hpp lsm_datatypes.cpp lsm_convert.hpp \
lsm_convert.cpp lsm_ipc.hpp lsm_ipc.cpp lsm_plugin_ipc.hpp \
- lsm_plugin_ipc.cpp util/qparams.c util/qparams.h
+ lsm_plugin_ipc.cpp util/qparams.c util/qparams.h lsm_scsi.c
diff --git a/c_binding/include/libstoragemgmt/Makefile.am b/c_binding/include/libstoragemgmt/Makefile.am
index 2a947f6..f7b8dbd 100644
--- a/c_binding/include/libstoragemgmt/Makefile.am
+++ b/c_binding/include/libstoragemgmt/Makefile.am
@@ -23,6 +23,7 @@ lsminc_HEADERS = \
libstoragemgmt_targetport.h \
libstoragemgmt_types.h \
libstoragemgmt_version.h \
+ libstoragemgmt_scsi.h \
libstoragemgmt_volumes.h


diff --git a/c_binding/include/libstoragemgmt/libstoragemgmt.h b/c_binding/include/libstoragemgmt/libstoragemgmt.h
index b902bd8..8450434 100644
--- a/c_binding/include/libstoragemgmt/libstoragemgmt.h
+++ b/c_binding/include/libstoragemgmt/libstoragemgmt.h
@@ -34,6 +34,7 @@
#include "libstoragemgmt_systems.h"
#include "libstoragemgmt_targetport.h"
#include "libstoragemgmt_volumes.h"
+#include "libstoragemgmt_scsi.h"


/*! \mainpage libStorageMgmt
diff --git a/c_binding/include/libstoragemgmt/libstoragemgmt_scsi.h b/c_binding/include/libstoragemgmt/libstoragemgmt_scsi.h
new file mode 100644
index 0000000..5a5dc24
--- /dev/null
+++ b/c_binding/include/libstoragemgmt/libstoragemgmt_scsi.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <***@redhat.com>
+ *
+ */
+
+#ifndef LIBSTORAGEMGMT_SCSI_H
+#define LIBSTORAGEMGMT_SCSI_H
+
+#include "libstoragemgmt_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Find out the scsi disk paths of given SCSI VPD page 0x83 NAA ID.
+ * New in version 1.3.
+ * @param[in] vpd83 String. The VPD83 ID retrieved from LSM volume or disk.
+ * for supported strip sizes.
+ * @param[out] sd_path_list.
+ * Output pointer of lsm_string_list. The format of scsi
+ * disk path will be "/dev/sd[a-z]+".
+ * NULL if no found or got error.
+ * Memory should be freed by lsm_string_list_free().
+ * @return LSM_ERR_OK on success.
+ * LSM_ERR_INVALID_ARGUMENT when any argument is NULL.
+ * LSM_ERR_NO_MEMORY when no memory.
+ * LSM_ERR_LIB_BUG when something unexpected happens.
+ */
+int LSM_DLL_EXPORT lsm_scsi_disk_paths_of_vpd83(const char *vpd83,
+ lsm_string_list **sd_path_list);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* LIBSTORAGEMGMT_SCSI_H */
diff --git a/c_binding/lsm_scsi.c b/c_binding/lsm_scsi.c
new file mode 100644
index 0000000..162ef68
--- /dev/null
+++ b/c_binding/lsm_scsi.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <***@redhat.com>
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <libudev.h>
+
+#include "libstoragemgmt/libstoragemgmt.h"
+#include "libstoragemgmt/libstoragemgmt_error.h"
+
+/*
+ * Using ID_WWN_WITH_EXTENSION udev property to match given VPD83.
+ * TODO(Gris Ge): Try to use /sys/block/sda/device/vpd_pg83 file as
+ * failback way or even replace current udev way if performance
+ * is good.
+ *
+ */
+int lsm_scsi_disk_paths_of_vpd83(const char *vpd83,
+ lsm_string_list **sd_path_list)
+
+{
+ struct udev *udev = NULL;
+ struct udev_enumerate *enumerate_sd = NULL;
+ struct udev_list_entry *sd_udevices = NULL;
+ struct udev_list_entry *sd_udev_list = NULL;
+ struct udev_list_entry *sd_udev_list_entry = NULL;
+ struct udev_device *sd_udev = NULL;
+ const char *sd_udev_path = NULL;
+ const char *sd_path = NULL;
+ char *wwn = NULL;
+ int rc = LSM_ERR_OK;
+ const char *dev_type = NULL;
+
+ if ((vpd83 == NULL) || (sd_path_list == NULL))
+ return LSM_ERR_INVALID_ARGUMENT;
+
+ *sd_path_list = NULL;
+
+ wwn = (char *) malloc(sizeof(char) *
+ (strlen(vpd83) + strlen("0x") + 1 /* tailing \0 */));
+
+ if (wwn == NULL) {
+ rc = LSM_ERR_NO_MEMORY;
+ goto out;
+ }
+
+ sprintf(wwn, "0x%s", vpd83);
+
+ udev = udev_new();
+ if (udev == NULL) {
+ rc = LSM_ERR_NO_MEMORY;
+ goto out;
+ }
+
+ enumerate_sd = udev_enumerate_new(udev);
+ if (enumerate_sd == NULL) {
+ rc = LSM_ERR_NO_MEMORY;
+ goto out;
+ }
+
+ if (udev_enumerate_add_match_subsystem(enumerate_sd, "block") != 0) {
+ rc = LSM_ERR_LIB_BUG;
+ goto out;
+ }
+
+ if (udev_enumerate_add_match_property(enumerate_sd, "ID_WWN_WITH_EXTENSION",
+ wwn) != 0) {
+ rc = LSM_ERR_LIB_BUG;
+ goto out;
+ }
+
+ if (udev_enumerate_scan_devices(enumerate_sd) != 0) {
+ rc = LSM_ERR_LIB_BUG;
+ goto out;
+ }
+
+ *sd_path_list = lsm_string_list_alloc(0 /* No pre-allocation */);
+ if (*sd_path_list == NULL) {
+ rc = LSM_ERR_NO_MEMORY;
+ goto out;
+ }
+ sd_udevices = udev_enumerate_get_list_entry(enumerate_sd);
+ udev_list_entry_foreach(sd_udev_list_entry, sd_udevices) {
+ sd_udev_path = udev_list_entry_get_name(sd_udev_list_entry);
+ if (sd_udev_path == NULL)
+ continue;
+
+ sd_udev = udev_device_new_from_syspath(udev, sd_udev_path);
+ if (sd_udev == NULL) {
+ rc = LSM_ERR_LIB_BUG;
+ goto out;
+ }
+
+ dev_type = udev_device_get_property_value(sd_udev, "DEVTYPE");
+ if ((dev_type == NULL) || (strcmp(dev_type, "disk") != 0)) {
+ udev_device_unref(sd_udev);
+ continue;
+ }
+
+ sd_path = udev_device_get_devnode(sd_udev);
+ if ((sd_path == NULL) ||
+ (strncmp(sd_path, "/dev/sd", strlen("/dev/sd")) != 0)) {
+ udev_device_unref(sd_udev);
+ continue;
+ }
+ if (lsm_string_list_append(*sd_path_list, sd_path) != 0) {
+ rc = LSM_ERR_NO_MEMORY;
+ goto out;
+ }
+ }
+
+ out:
+ if (udev != NULL) {
+ udev_unref(udev);
+ }
+ if (enumerate_sd != NULL) {
+ udev_enumerate_unref(enumerate_sd);
+ }
+
+ free(wwn);
+
+ if (*sd_path_list != NULL) {
+ if ((rc != LSM_ERR_OK) || (lsm_string_list_size(*sd_path_list) == 0)) {
+ lsm_string_list_free(*sd_path_list);
+ *sd_path_list = NULL;
+ }
+ }
+
+ return rc;
+}
diff --git a/configure.ac b/configure.ac
index beae390..53acb41 100644
--- a/configure.ac
+++ b/configure.ac
@@ -162,6 +162,8 @@ AM_PATH_PYTHON([2.6], [], AC_MSG_ERROR([Python interpreter 2.6 or 2.7 required])
AC_PYTHON_MODULE([pywbem], [Required])
AC_PYTHON_MODULE([M2Crypto], [Required])
AC_PYTHON_MODULE([argparse], [Required])
+AC_PYTHON_MODULE([pyudev], [Required])
+PKG_CHECK_MODULES([LIBUDEV], [libudev])

dnl ==========================================================================
dnl Check for libmicrohttpd and json-c as it is needed for REST API daemon
--
1.8.3.1
Gris Ge
2015-11-09 05:49:06 UTC
Permalink
* New function lsm.SCSI.disk_names_of_vpd83() to search all matching
SCSI disks(format: sdx) for given VPD83 ID.

Signed-off-by: Gris Ge <***@redhat.com>
---
python_binding/Makefile.am | 1 +
python_binding/lsm/__init__.py | 2 ++
python_binding/lsm/_scsi.py | 53 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 56 insertions(+)
create mode 100644 python_binding/lsm/_scsi.py

diff --git a/python_binding/Makefile.am b/python_binding/Makefile.am
index 8b0581a..0fe1a6d 100644
--- a/python_binding/Makefile.am
+++ b/python_binding/Makefile.am
@@ -10,6 +10,7 @@ lsm_PYTHON = \
lsm/_transport.py \
lsm/version.py \
lsm/_iplugin.py \
+ lsm/_scsi.py \
lsm/_pluginrunner.py

external_PYTHON = \
diff --git a/python_binding/lsm/__init__.py b/python_binding/lsm/__init__.py
index fb1cdbd..eb3a10e 100644
--- a/python_binding/lsm/__init__.py
+++ b/python_binding/lsm/__init__.py
@@ -2,6 +2,8 @@

from version import VERSION

+from lsm._scsi import SCSI
+
from _common import error, info, LsmError, ErrorNumber, \
JobStatus, uri_parse, md5, Proxy, size_bytes_2_size_human, \
common_urllib2_error_handler, size_human_2_size_bytes
diff --git a/python_binding/lsm/_scsi.py b/python_binding/lsm/_scsi.py
new file mode 100644
index 0000000..3d06a45
--- /dev/null
+++ b/python_binding/lsm/_scsi.py
@@ -0,0 +1,53 @@
+# Copyright (C) 2015 Red Hat, Inc.
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Gris Ge <***@redhat.com>
+
+## TODO(Gris Ge): Try to use use C API lsm_scsi_disk_name_list_of_vpd83()
+## instead of duplicate udev call here:
+## https://docs.python.org/2/extending/extending.html
+
+import pyudev
+
+class SCSI(object):
+ @staticmethod
+ def disk_names_of_vpd83(vpd83):
+ """
+ Version:
+ 1.3
+ Usage:
+ Find out the sdX name for given SCSI VPD page 0x83 NAA type ID.
+ Parameters:
+ vpd83 (string)
+ The VPD83 NAA type ID.
+ Returns:
+ sd_name (list of string)
+ Empty list is not found. The string format is 'sdz'.
+
+ SpecialExceptions:
+ N/A
+ Capability:
+ N/A
+ No capability required from plugin as this is a library level
+ method.
+ """
+ rc = []
+ context = pyudev.Context()
+ wwn = '0x%s' % vpd83
+ for dev in context.list_devices(subsystem='block',
+ ID_WWN_WITH_EXTENSION=wwn):
+ sd_path = str(dev.device_node)
+ if sd_path.startswith("/dev/sd") and dev['DEVTYPE'] == "disk":
+ rc.append(sd_path[len("/dev/"):])
+ return rc
--
1.8.3.1
Gris Ge
2015-11-09 05:49:07 UTC
Permalink
* New function lsm.SCSI.disk_paths_of_vpd83() to search all matching
SCSI disk paths(format: /dev/sd[a-z]+) for given VPD83 ID.

Signed-off-by: Gris Ge <***@redhat.com>
---
python_binding/Makefile.am | 1 +
python_binding/lsm/__init__.py | 2 ++
python_binding/lsm/_scsi.py | 55 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 58 insertions(+)
create mode 100644 python_binding/lsm/_scsi.py

diff --git a/python_binding/Makefile.am b/python_binding/Makefile.am
index 8b0581a..0fe1a6d 100644
--- a/python_binding/Makefile.am
+++ b/python_binding/Makefile.am
@@ -10,6 +10,7 @@ lsm_PYTHON = \
lsm/_transport.py \
lsm/version.py \
lsm/_iplugin.py \
+ lsm/_scsi.py \
lsm/_pluginrunner.py

external_PYTHON = \
diff --git a/python_binding/lsm/__init__.py b/python_binding/lsm/__init__.py
index fb1cdbd..eb3a10e 100644
--- a/python_binding/lsm/__init__.py
+++ b/python_binding/lsm/__init__.py
@@ -2,6 +2,8 @@

from version import VERSION

+from lsm._scsi import SCSI
+
from _common import error, info, LsmError, ErrorNumber, \
JobStatus, uri_parse, md5, Proxy, size_bytes_2_size_human, \
common_urllib2_error_handler, size_human_2_size_bytes
diff --git a/python_binding/lsm/_scsi.py b/python_binding/lsm/_scsi.py
new file mode 100644
index 0000000..c9f6d57
--- /dev/null
+++ b/python_binding/lsm/_scsi.py
@@ -0,0 +1,55 @@
+# Copyright (C) 2015 Red Hat, Inc.
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Gris Ge <***@redhat.com>
+
+## TODO(Gris Ge): Try to use use C API lsm_scsi_disk_name_list_of_vpd83()
+## instead of duplicate udev call here:
+## https://docs.python.org/2/extending/extending.html
+
+import pyudev
+
+class SCSI(object):
+ @staticmethod
+ def disk_paths_of_vpd83(vpd83):
+ """
+ Version:
+ 1.3
+ Usage:
+ Find out the /dev/sdX paths for given SCSI VPD page 0x83 NAA type
+ ID. Considering multipath, certain VPD83 will got multiple disks
+ associated.
+ Parameters:
+ vpd83 (string)
+ The VPD83 NAA type ID.
+ Returns:
+ sd_name (list of string)
+ Empty list is not found. The string format is '/dev/sd[a-z]+'.
+
+ SpecialExceptions:
+ N/A
+ Capability:
+ N/A
+ No capability required from plugin as this is a library level
+ method.
+ """
+ rc = []
+ context = pyudev.Context()
+ wwn = '0x%s' % vpd83
+ for dev in context.list_devices(subsystem='block',
+ ID_WWN_WITH_EXTENSION=wwn):
+ sd_path = str(dev.device_node)
+ if sd_path.startswith("/dev/sd") and dev['DEVTYPE'] == "disk":
+ rc.append(sd_path)
+ return rc
--
1.8.3.1
Gris Ge
2015-11-09 05:49:08 UTC
Permalink
* The `lsmcli list --type volumes` will include local scsi disks if VPD83
matches. Example:

$ lsmcli lv -s
--------------------------------
ID | VOL_ID_00001
Name | test
SCSI VPD 0x83 | 53333330000007d0
Block Size | 512
Block Count | 2097152
Size | 1073741824
Disabled | No
Pool ID | POOL_ID_00001
System ID | sim-01
Disk Names | sdb
| sdd
| sdf
| sdh
--------------------------------

Signed-off-by: Gris Ge <***@redhat.com>
---
tools/lsmcli/cmdline.py | 35 +++++++++++++++++++++++------------
tools/lsmcli/data_display.py | 1 +
2 files changed, 24 insertions(+), 12 deletions(-)

diff --git a/tools/lsmcli/cmdline.py b/tools/lsmcli/cmdline.py
index c66eaf2..563abe1 100644
--- a/tools/lsmcli/cmdline.py
+++ b/tools/lsmcli/cmdline.py
@@ -34,7 +34,7 @@
from lsm import (Client, Pool, VERSION, LsmError, Disk,
Volume, JobStatus, ErrorNumber, BlockRange,
uri_parse, Proxy, size_human_2_size_bytes,
- AccessGroup, FileSystem, NfsExport, TargetPort)
+ AccessGroup, FileSystem, NfsExport, TargetPort, SCSI)

from lsm.lsmcli.data_display import (
DisplayData, PlugData, out,
@@ -904,20 +904,24 @@ def list(self, args):
search_value = args.tgt

if args.type == 'VOLUMES':
+ lsm_vols = []
if search_key == 'volume_id':
search_key = 'id'
if search_key == 'access_group_id':
lsm_ag = _get_item(self.c.access_groups(), args.ag,
"Access Group", raise_error=False)
if lsm_ag:
- return self.display_data(
- self.c.volumes_accessible_by_access_group(lsm_ag))
- else:
- return self.display_data([])
+ lsm_vols = self.c.volumes_accessible_by_access_group(
+ lsm_ag)
elif search_key and search_key not in Volume.SUPPORTED_SEARCH_KEYS:
raise ArgError("Search key '%s' is not supported by "
"volume listing." % search_key)
- self.display_data(self.c.volumes(search_key, search_value))
+ else:
+ lsm_vols = self.c.volumes(search_key, search_value)
+
+ self.display_data(
+ list(self._vol_add_sd_names(v) for v in lsm_vols))
+
elif args.type == 'POOLS':
if search_key == 'pool_id':
search_key = 'id'
@@ -1023,7 +1027,7 @@ def access_group_volumes(self, args):
agl = self.c.access_groups()
group = _get_item(agl, args.ag, "Access Group")
vols = self.c.volumes_accessible_by_access_group(group)
- self.display_data(vols)
+ self.display_data(list(self._vol_add_sd_names(v) for v in vols))

def iscsi_chap(self, args):
(init_id, init_type) = parse_convert_init(args.init)
@@ -1163,7 +1167,7 @@ def volume_create(self, args):
args.name,
self._size(args.size),
vol_provision_str_to_type(args.provisioning)))
- self.display_data([vol])
+ self.display_data([self._vol_add_sd_names(vol)])

## Creates a snapshot
def fs_snap_create(self, args):
@@ -1271,7 +1275,7 @@ def volume_replicate(self, args):
vol = self._wait_for_it(
"replicate volume",
*self.c.volume_replicate(p, rep_type, v, args.name))
- self.display_data([vol])
+ self.display_data([self._vol_add_sd_names(vol)])

## Replicates a range of a volume
def volume_replicate_range(self, args):
@@ -1324,7 +1328,7 @@ def volume_resize(self, args):
if self.confirm_prompt(False):
vol = self._wait_for_it("resize",
*self.c.volume_resize(v, size))
- self.display_data([vol])
+ self.display_data([self._vol_add_sd_names(vol)])

## Enable a volume
def volume_enable(self, args):
@@ -1413,8 +1417,9 @@ def volume_raid_create(self, args):
strip_size = Volume.VCR_STRIP_SIZE_DEFAULT

self.display_data([
- self.c.volume_raid_create(
- args.name, raid_type, lsm_disks, strip_size)])
+ self._vol_add_sd_names(
+ self.c.volume_raid_create(
+ args.name, raid_type, lsm_disks, strip_size))])

def volume_raid_create_cap(self, args):
lsm_sys = _get_item(self.c.systems(), args.sys, "System")
@@ -1536,3 +1541,9 @@ def process(self, cli=None):

self.args.func(self.args)
self.shutdown()
+
+ def _vol_add_sd_names(self, lsm_vol):
+ lsm_vol.sd_names = []
+ if len(lsm_vol.vpd83) > 0:
+ lsm_vol.sd_names = SCSI.disk_names_of_vpd83(lsm_vol.vpd83)
+ return lsm_vol
diff --git a/tools/lsmcli/data_display.py b/tools/lsmcli/data_display.py
index 2feda46..9318580 100644
--- a/tools/lsmcli/data_display.py
+++ b/tools/lsmcli/data_display.py
@@ -418,6 +418,7 @@ def __init__(self):
VOL_HEADER['admin_state'] = 'Disabled'
VOL_HEADER['pool_id'] = 'Pool ID'
VOL_HEADER['system_id'] = 'System ID'
+ VOL_HEADER['sd_names'] = 'Disk Names' # This is appended by cmdline.py

VOL_COLUMN_SKIP_KEYS = ['block_size', 'num_of_blocks']
--
1.8.3.1
Gris Ge
2015-11-09 05:49:09 UTC
Permalink
* The `lsmcli list --type volumes` will include local scsi disks if VPD83
matches. Example:

$ lsmcli lv -s
--------------------------------
ID | VOL_ID_00001
Name | test
SCSI VPD 0x83 | 53333330000007d0
Block Size | 512
Block Count | 2097152
Size | 1073741824
Disabled | No
Pool ID | POOL_ID_00001
System ID | sim-01
Disk Paths | /dev/sda
| /dev/sdf
| /dev/sdh
| /dev/sdj
--------------------------------

Signed-off-by: Gris Ge <***@redhat.com>
---
tools/lsmcli/cmdline.py | 35 +++++++++++++++++++++++------------
tools/lsmcli/data_display.py | 1 +
2 files changed, 24 insertions(+), 12 deletions(-)

diff --git a/tools/lsmcli/cmdline.py b/tools/lsmcli/cmdline.py
index c66eaf2..0b81ced 100644
--- a/tools/lsmcli/cmdline.py
+++ b/tools/lsmcli/cmdline.py
@@ -34,7 +34,7 @@
from lsm import (Client, Pool, VERSION, LsmError, Disk,
Volume, JobStatus, ErrorNumber, BlockRange,
uri_parse, Proxy, size_human_2_size_bytes,
- AccessGroup, FileSystem, NfsExport, TargetPort)
+ AccessGroup, FileSystem, NfsExport, TargetPort, SCSI)

from lsm.lsmcli.data_display import (
DisplayData, PlugData, out,
@@ -904,20 +904,24 @@ def list(self, args):
search_value = args.tgt

if args.type == 'VOLUMES':
+ lsm_vols = []
if search_key == 'volume_id':
search_key = 'id'
if search_key == 'access_group_id':
lsm_ag = _get_item(self.c.access_groups(), args.ag,
"Access Group", raise_error=False)
if lsm_ag:
- return self.display_data(
- self.c.volumes_accessible_by_access_group(lsm_ag))
- else:
- return self.display_data([])
+ lsm_vols = self.c.volumes_accessible_by_access_group(
+ lsm_ag)
elif search_key and search_key not in Volume.SUPPORTED_SEARCH_KEYS:
raise ArgError("Search key '%s' is not supported by "
"volume listing." % search_key)
- self.display_data(self.c.volumes(search_key, search_value))
+ else:
+ lsm_vols = self.c.volumes(search_key, search_value)
+
+ self.display_data(
+ list(self._vol_add_sd_paths(v) for v in lsm_vols))
+
elif args.type == 'POOLS':
if search_key == 'pool_id':
search_key = 'id'
@@ -1023,7 +1027,7 @@ def access_group_volumes(self, args):
agl = self.c.access_groups()
group = _get_item(agl, args.ag, "Access Group")
vols = self.c.volumes_accessible_by_access_group(group)
- self.display_data(vols)
+ self.display_data(list(self._vol_add_sd_paths(v) for v in vols))

def iscsi_chap(self, args):
(init_id, init_type) = parse_convert_init(args.init)
@@ -1163,7 +1167,7 @@ def volume_create(self, args):
args.name,
self._size(args.size),
vol_provision_str_to_type(args.provisioning)))
- self.display_data([vol])
+ self.display_data([self._vol_add_sd_paths(vol)])

## Creates a snapshot
def fs_snap_create(self, args):
@@ -1271,7 +1275,7 @@ def volume_replicate(self, args):
vol = self._wait_for_it(
"replicate volume",
*self.c.volume_replicate(p, rep_type, v, args.name))
- self.display_data([vol])
+ self.display_data([self._vol_add_sd_paths(vol)])

## Replicates a range of a volume
def volume_replicate_range(self, args):
@@ -1324,7 +1328,7 @@ def volume_resize(self, args):
if self.confirm_prompt(False):
vol = self._wait_for_it("resize",
*self.c.volume_resize(v, size))
- self.display_data([vol])
+ self.display_data([self._vol_add_sd_paths(vol)])

## Enable a volume
def volume_enable(self, args):
@@ -1413,8 +1417,9 @@ def volume_raid_create(self, args):
strip_size = Volume.VCR_STRIP_SIZE_DEFAULT

self.display_data([
- self.c.volume_raid_create(
- args.name, raid_type, lsm_disks, strip_size)])
+ self._vol_add_sd_paths(
+ self.c.volume_raid_create(
+ args.name, raid_type, lsm_disks, strip_size))])

def volume_raid_create_cap(self, args):
lsm_sys = _get_item(self.c.systems(), args.sys, "System")
@@ -1536,3 +1541,9 @@ def process(self, cli=None):

self.args.func(self.args)
self.shutdown()
+
+ def _vol_add_sd_paths(self, lsm_vol):
+ lsm_vol.sd_paths = []
+ if len(lsm_vol.vpd83) > 0:
+ lsm_vol.sd_paths = SCSI.disk_paths_of_vpd83(lsm_vol.vpd83)
+ return lsm_vol
diff --git a/tools/lsmcli/data_display.py b/tools/lsmcli/data_display.py
index 2feda46..614d477 100644
--- a/tools/lsmcli/data_display.py
+++ b/tools/lsmcli/data_display.py
@@ -418,6 +418,7 @@ def __init__(self):
VOL_HEADER['admin_state'] = 'Disabled'
VOL_HEADER['pool_id'] = 'Pool ID'
VOL_HEADER['system_id'] = 'System ID'
+ VOL_HEADER['sd_paths'] = 'Disk Paths' # This is appended by cmdline.py

VOL_COLUMN_SKIP_KEYS = ['block_size', 'num_of_blocks']
--
1.8.3.1
Gris Ge
2015-11-09 05:49:10 UTC
Permalink
* Simply test LSM_ERR_INVALID_ARGUMENT of lsm_scsi_disk_names_of_vpd83().

Signed-off-by: Gris Ge <***@redhat.com>
---
test/tester.c | 37 +++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)

diff --git a/test/tester.c b/test/tester.c
index da2a3a4..357e7c4 100644
--- a/test/tester.c
+++ b/test/tester.c
@@ -36,6 +36,7 @@ const char *ISCSI_HOST[2] = { "iqn.1994-05.com.domain:01.89bd01",
static int which_plugin = 0;

#define POLL_SLEEP 50000
+#define VPD83_TO_SEARCH "600508b1001c79ade5178f0626caaa9c"

lsm_connect *c = NULL;

@@ -3083,6 +3084,42 @@ START_TEST(test_volume_raid_create)
}
END_TEST

+
+/*
+ * Just check whether LSM_ERR_INVALID_ARGUMENT handle correctly.
+ */
+START_TEST(test_scsi_disk_names_of_vpd83)
+{
+ int rc;
+ lsm_string_list *sd_name_list = NULL;
+
+ if (which_plugin == 1){
+ /* silently skip on simc, no need for duplicate test. */
+ return;
+ }
+ rc = lsm_scsi_disk_names_of_vpd83(NULL, &sd_name_list);
+ fail_unless(
+ rc == LSM_ERR_INVALID_ARGUMENT,
+ "lsm_scsi_disk_names_of_vpd83(): Expecting LSM_ERR_INVALID_ARGUMENT "
+ "when vpd83 argument pointer is NULL");
+
+ rc = lsm_scsi_disk_names_of_vpd83(VPD83_TO_SEARCH, NULL);
+ fail_unless(
+ rc == LSM_ERR_INVALID_ARGUMENT,
+ "lsm_scsi_disk_names_of_vpd83(): Expecting LSM_ERR_INVALID_ARGUMENT "
+ "when sd_name_list argument pointer is NULL");
+
+ rc = lsm_scsi_disk_names_of_vpd83(VPD83_TO_SEARCH, &sd_name_list);
+ fail_unless(
+ rc == LSM_ERR_OK,
+ "lsm_scsi_disk_names_of_vpd83(): Expecting LSM_ERR_OK"
+ "when no argument is NULL");
+ if (sd_name_list != NULL)
+ lsm_string_list_free(sd_name_list);
+}
+END_TEST
+
+
Suite * lsm_suite(void)
{
Suite *s = suite_create("libStorageMgmt");
--
1.8.3.1
Gris Ge
2015-11-09 05:49:11 UTC
Permalink
* Test LSM_ERR_INVALID_ARGUMENT of lsm_scsi_disk_paths_of_vpd83().
* Test dangling pointer of 'sd_path_list' output pointer.

Signed-off-by: Gris Ge <***@redhat.com>
---
test/tester.c | 42 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)

diff --git a/test/tester.c b/test/tester.c
index da2a3a4..d51326d 100644
--- a/test/tester.c
+++ b/test/tester.c
@@ -36,6 +36,7 @@ const char *ISCSI_HOST[2] = { "iqn.1994-05.com.domain:01.89bd01",
static int which_plugin = 0;

#define POLL_SLEEP 50000
+#define VPD83_TO_SEARCH "600508b1001c79ade5178f0626caaa9c"

lsm_connect *c = NULL;

@@ -3083,6 +3084,47 @@ START_TEST(test_volume_raid_create)
}
END_TEST

+
+/*
+ * Just check whether LSM_ERR_INVALID_ARGUMENT handle correctly.
+ */
+START_TEST(test_scsi_disk_paths_of_vpd83)
+{
+ int rc = LSM_ERR_OK;
+ lsm_string_list *sd_path_list;
+ /* Not initialized in order to test dangling pointer sd_path_list */
+
+ if (which_plugin == 1){
+ /* silently skip on simc, no need for duplicate test. */
+ return;
+ }
+
+ rc = lsm_scsi_disk_paths_of_vpd83(NULL, &sd_path_list);
+ fail_unless(rc == LSM_ERR_INVALID_ARGUMENT,
+ "lsm_scsi_disk_paths_of_vpd83(): Expecting "
+ "LSM_ERR_INVALID_ARGUMENT when vpd83 argument pointer is NULL");
+
+ fail_unless(sd_path_list == NULL,
+ "lsm_scsi_disk_paths_of_vpd83(): Expecting "
+ "sd_path_list been set as NULL.");
+
+ rc = lsm_scsi_disk_paths_of_vpd83(VPD83_TO_SEARCH, NULL);
+ fail_unless(rc == LSM_ERR_INVALID_ARGUMENT,
+ "lsm_scsi_disk_paths_of_vpd83(): Expecting "
+ "LSM_ERR_INVALID_ARGUMENT when sd_path_list argument pointer "
+ "is NULL");
+
+ rc = lsm_scsi_disk_paths_of_vpd83(VPD83_TO_SEARCH, &sd_path_list);
+ fail_unless(rc == LSM_ERR_OK,
+ "lsm_scsi_disk_paths_of_vpd83(): Expecting LSM_ERR_OK"
+ "when no argument is NULL");
+
+ if (sd_path_list != NULL)
+ lsm_string_list_free(sd_path_list);
+}
+END_TEST
+
+
Suite * lsm_suite(void)
{
Suite *s = suite_create("libStorageMgmt");
--
1.8.3.1
Gris Ge
2015-11-09 05:49:12 UTC
Permalink
* Add the new python_binding/lsm/_scsi.py file.

Signed-off-by: Gris Ge <***@redhat.com>
---
packaging/libstoragemgmt.spec.in | 1 +
1 file changed, 1 insertion(+)

diff --git a/packaging/libstoragemgmt.spec.in b/packaging/libstoragemgmt.spec.in
index 00da8c8..f109dfa 100644
--- a/packaging/libstoragemgmt.spec.in
+++ b/packaging/libstoragemgmt.spec.in
@@ -540,6 +540,7 @@ fi
%{python_sitelib}/lsm/external/*
%{python_sitelib}/lsm/_client.*
%{python_sitelib}/lsm/_common.*
+%{python_sitelib}/lsm/_scsi.*
%{python_sitelib}/lsm/_data.*
%{python_sitelib}/lsm/_iplugin.*
%{python_sitelib}/lsm/_pluginrunner.*
--
1.8.3.1
Gris Ge
2015-11-09 05:49:13 UTC
Permalink
* Just allow python absolute import like:
from lsm._scsi import SCSI

Signed-off-by: Gris Ge <***@redhat.com>
---
tools/utility/check_const.pl | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/tools/utility/check_const.pl b/tools/utility/check_const.pl
index 64abf34..2b2eead 100644
--- a/tools/utility/check_const.pl
+++ b/tools/utility/check_const.pl
@@ -267,7 +267,14 @@ sub _parse_py_init_file($) {

foreach my $line (@lines) {
if ( $line =~ /from ([^ ]+) import (.+)$/ ) {
- push @rc1, sprintf "%s/%s.py", $folder_path, $1;
+ my $module_file_name = $1;
+ if ($module_file_name =~ /^lsm\.(.+)$/) {
+ $module_file_name = $1;
+ $module_file_name =~ s|\.|/|g;
+ push @rc1, sprintf "%s/%s.py", $folder_path, $module_file_name;
+ } else {
+ push @rc1, sprintf "%s/%s.py", $folder_path, $module_file_name;
+ }
my $class_line = $2;
while ( $class_line =~ /([A-Z][a-zA-Z]+)[, \\]*/g ) {
push @rc2, $1;
--
1.8.3.1
Gris Ge
2015-11-09 05:49:14 UTC
Permalink
* New "Disk Name" column added to volume listing, which cause list[-2]
does not pointing to pool id, changed it to index number 5.

Signed-off-by: Gris Ge <***@redhat.com>
---
test/cmdtest.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/cmdtest.py b/test/cmdtest.py
index 7fa6599..bbf39a4 100755
--- a/test/cmdtest.py
+++ b/test/cmdtest.py
@@ -750,7 +750,7 @@ def volume_raid_create_test(cap, system_id):

volume = parse(out)
vol_id = volume[0][0]
- pool_id = volume[0][-2]
+ pool_id = volume[0][5]

if cap['VOLUME_RAID_INFO']:
out = call(
--
1.8.3.1
Gris Ge
2015-11-09 05:49:15 UTC
Permalink
* Use random generated volume name for volume_raid_create_test() test.

Signed-off-by: Gris Ge <***@redhat.com>
---
test/cmdtest.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/test/cmdtest.py b/test/cmdtest.py
index bbf39a4..22ee372 100755
--- a/test/cmdtest.py
+++ b/test/cmdtest.py
@@ -745,7 +745,8 @@ def volume_raid_create_test(cap, system_id):

out = call([
cmd, '-t' + sep, 'volume-raid-create', '--disk', free_disk_ids[0],
- '--disk', free_disk_ids[1], '--name', 'test_volume_raid_create',
+ '--disk', free_disk_ids[1], '--name',
+ 'test_volume_raid_create_%s' % rs(4),
'--raid-type', 'raid1'])[1]

volume = parse(out)
--
1.8.3.1
Gris Ge
2015-11-09 05:49:16 UTC
Permalink
* New these packages for libudev and pyudev:
* python-pyudev
* libudev-dev

Signed-off-by: Gris Ge <***@redhat.com>
---
.travis.yml | 2 ++
1 file changed, 2 insertions(+)

diff --git a/.travis.yml b/.travis.yml
index f267aed..abae161 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -19,6 +19,8 @@ addons:
- python-m2crypto
- libssl-dev
- libconfig-dev
+ - python-pyudev
+ - libudev-dev

compiler: gcc
--
1.8.3.1
Gris Ge
2015-11-09 06:14:17 UTC
Permalink
Post by Gris Ge
* API name changed to lsm_scsi_disk_paths_of_vpd83() and
lsm.SCSI.disk_paths_of_vpd83().
* Fixed dangling pointer of sd_path_list.
* Add test for dangling pointer of sd_path_list.
* Changed lsmcli output name as Disk Paths.
Sorry, I incorrectly included the old patches.
Please ignore patches without 'PATCH V2' title.

Thank you.
Best regards.
--
Gris Ge
Gris Ge
2015-11-17 07:30:25 UTC
Permalink
* API for querying scsi disk paths from VPD83 ID.
C:
int lsm_scsi_disk_paths_of_vpd83(const char *vpd83,
lsm_string_list **sd_path_list,
lsm_error **lsm_err)

Python:
lsm.SCSI.disk_paths_of_vpd83(vpd83)

* lsmcli changes: add "Disk Paths", example:

lsmcli lv -s
--------------------------------
ID | VOL_ID_00001
Name | lsm_RDIQVLWJYZKK
SCSI VPD 0x83 | 53333330000007d0
Block Size | 512
Block Count | 61440
Size | 31457280
Disabled | No
Pool ID | POOL_ID_00004
System ID | sim-01
Disk Paths | /dev/sdb
| /dev/sdd
| /dev/sdf
| /dev/sdh
--------------------------------

Github pull request is:
https://github.com/libstorage/libstoragemgmt/pull/71

Changes in V2:

* API name changed to lsm_scsi_disk_paths_of_vpd83() and
lsm.SCSI.disk_paths_of_vpd83().
* Fixed dangling pointer of sd_path_list.
* Add test for dangling pointer of sd_path_list.
* Changed lsmcli output name as Disk Paths.

Changes in V3:

* Add 'lsm_error ** lsm_err' argument to received error message.
* Try sysfs vpd83 file fist, if not support, use udev.
* Change python module to C extension of C API.

Gris Ge (11):
C API: New function for SCSI disk path matching.
Python API: New function for SCSI disk path matching.
lsmcli: Add SCSI disk paths in output of volume listing.
Test: Fix missing lsm.SCSI module.
C unit test: Test case for lsm_scsi_disk_paths_of_vpd83()
RPM SPEC: Add new python library file.
Constant check: Support python absolute import.
lsmcli test: Fix failed test case caused by new disk name colume.
lsmcli test: Fix test case volume_raid_create_test()
Travis CI: Add new compile dependency.
Test: Fix incorrect clean up for distcheck.

.travis.yml | 2 +
c_binding/Makefile.am | 8 +-
c_binding/include/libstoragemgmt/Makefile.am | 1 +
c_binding/include/libstoragemgmt/libstoragemgmt.h | 1 +
.../include/libstoragemgmt/libstoragemgmt_scsi.h | 55 +++
c_binding/lsm_scsi.c | 419 +++++++++++++++++++++
configure.ac | 2 +
packaging/libstoragemgmt.spec.in | 9 +-
python_binding/Makefile.am | 9 +
python_binding/lsm/__init__.py | 3 +
python_binding/lsm/_scsi.c | 110 ++++++
test/cmdtest.py | 5 +-
test/runtests.sh | 13 +-
test/tester.c | 65 ++++
tools/lsmcli/cmdline.py | 35 +-
tools/lsmcli/data_display.py | 1 +
tools/lsmenv | 4 +
tools/utility/check_const.pl | 9 +-
18 files changed, 725 insertions(+), 26 deletions(-)
create mode 100644 c_binding/include/libstoragemgmt/libstoragemgmt_scsi.h
create mode 100644 c_binding/lsm_scsi.c
create mode 100644 python_binding/lsm/_scsi.c
--
1.8.3.1
Gris Ge
2015-11-17 07:30:26 UTC
Permalink
* New method lsm_scsi_disk_paths_of_vpd83() takes VPD83 ID to find out
all matching scsi disk paths(format:/dev/sd[a-z]+).

Signed-off-by: Gris Ge <***@redhat.com>
---
c_binding/Makefile.am | 8 +-
c_binding/include/libstoragemgmt/Makefile.am | 1 +
c_binding/include/libstoragemgmt/libstoragemgmt.h | 1 +
.../include/libstoragemgmt/libstoragemgmt_scsi.h | 55 +++
c_binding/lsm_scsi.c | 419 +++++++++++++++++++++
configure.ac | 1 +
6 files changed, 482 insertions(+), 3 deletions(-)
create mode 100644 c_binding/include/libstoragemgmt/libstoragemgmt_scsi.h
create mode 100644 c_binding/lsm_scsi.c

diff --git a/c_binding/Makefile.am b/c_binding/Makefile.am
index e4b8e1b..18da493 100644
--- a/c_binding/Makefile.am
+++ b/c_binding/Makefile.am
@@ -3,13 +3,15 @@ SUBDIRS = include
AM_CPPFLAGS = -I$(top_srcdir)/c_binding/include \
-I$(top_builddir)/c_binding/include \
-***@srcdir@/c_binding/include \
- $(LIBXML_CFLAGS) $(LIBGLIB_CFLAGS)
+ $(LIBXML_CFLAGS) $(LIBGLIB_CFLAGS) \
+ $(LIBUDEV_CFLAGS)

lib_LTLIBRARIES = libstoragemgmt.la

-libstoragemgmt_la_LIBADD=$(LIBXML_LIBS) $(YAJL_LIBS) $(LIBGLIB_LIBS)
+libstoragemgmt_la_LIBADD=$(LIBXML_LIBS) $(YAJL_LIBS) $(LIBGLIB_LIBS) \
+ $(LIBUDEV_LIBS)
libstoragemgmt_la_LDFLAGS= -version-info $(LIBSM_LIBTOOL_VERSION)
libstoragemgmt_la_SOURCES= \
lsm_mgmt.cpp lsm_datatypes.hpp lsm_datatypes.cpp lsm_convert.hpp \
lsm_convert.cpp lsm_ipc.hpp lsm_ipc.cpp lsm_plugin_ipc.hpp \
- lsm_plugin_ipc.cpp util/qparams.c util/qparams.h
+ lsm_plugin_ipc.cpp util/qparams.c util/qparams.h lsm_scsi.c
diff --git a/c_binding/include/libstoragemgmt/Makefile.am b/c_binding/include/libstoragemgmt/Makefile.am
index 2a947f6..f7b8dbd 100644
--- a/c_binding/include/libstoragemgmt/Makefile.am
+++ b/c_binding/include/libstoragemgmt/Makefile.am
@@ -23,6 +23,7 @@ lsminc_HEADERS = \
libstoragemgmt_targetport.h \
libstoragemgmt_types.h \
libstoragemgmt_version.h \
+ libstoragemgmt_scsi.h \
libstoragemgmt_volumes.h


diff --git a/c_binding/include/libstoragemgmt/libstoragemgmt.h b/c_binding/include/libstoragemgmt/libstoragemgmt.h
index b902bd8..8450434 100644
--- a/c_binding/include/libstoragemgmt/libstoragemgmt.h
+++ b/c_binding/include/libstoragemgmt/libstoragemgmt.h
@@ -34,6 +34,7 @@
#include "libstoragemgmt_systems.h"
#include "libstoragemgmt_targetport.h"
#include "libstoragemgmt_volumes.h"
+#include "libstoragemgmt_scsi.h"


/*! \mainpage libStorageMgmt
diff --git a/c_binding/include/libstoragemgmt/libstoragemgmt_scsi.h b/c_binding/include/libstoragemgmt/libstoragemgmt_scsi.h
new file mode 100644
index 0000000..a229692
--- /dev/null
+++ b/c_binding/include/libstoragemgmt/libstoragemgmt_scsi.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <***@redhat.com>
+ *
+ */
+
+#ifndef LIBSTORAGEMGMT_SCSI_H
+#define LIBSTORAGEMGMT_SCSI_H
+
+#include "libstoragemgmt_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Find out the scsi disk paths of given SCSI VPD page 0x83 NAA ID.
+ * New in version 1.3.
+ * @param[in] vpd83 String. The VPD83 ID retrieved from LSM volume or disk.
+ * for supported strip sizes.
+ * @param[out] sd_path_list
+ * Output pointer of lsm_string_list. The format of scsi
+ * disk path will be "/dev/sd[a-z]+".
+ * NULL if no found or got error.
+ * Memory should be freed by lsm_string_list_free().
+ * @param[out] lsm_err
+ * Output pointer of lsm_error. Error message could be
+ * retrived via lsm_error_message_get(). Memory should be
+ * freed by lsm_error_free().
+ * @return LSM_ERR_OK on success.
+ * LSM_ERR_INVALID_ARGUMENT when any argument is NULL.
+ * LSM_ERR_NO_MEMORY when no memory.
+ * LSM_ERR_LIB_BUG when something unexpected happens.
+ */
+int LSM_DLL_EXPORT lsm_scsi_disk_paths_of_vpd83(const char *vpd83,
+ lsm_string_list **sd_path_list,
+ lsm_error **lsm_err);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* LIBSTORAGEMGMT_SCSI_H */
diff --git a/c_binding/lsm_scsi.c b/c_binding/lsm_scsi.c
new file mode 100644
index 0000000..a488f48
--- /dev/null
+++ b/c_binding/lsm_scsi.c
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <***@redhat.com>
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <libudev.h>
+#include <stdbool.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "libstoragemgmt/libstoragemgmt.h"
+#include "libstoragemgmt/libstoragemgmt_error.h"
+#include "libstoragemgmt/libstoragemgmt_plug_interface.h"
+
+#define _MAX_VPD83_LEN 0xff + 4
+#define _MAX_NAA_ID_LEN 33 /* Max one is 6h IEEE Registered Extended ID */
+#define _SYS_BLOCK_PATH "/sys/block"
+
+#define _T10_VPD83_NAA_235_ID_LEN 8
+#define _T10_VPD83_NAA_6_ID_LEN 16
+#define _T10_VPD83_PAGE_CODE 0x83
+#define _T10_VPD83_DESIGNATOR_TYPE_NAA 0x3
+#define _T10_VPD83_NAA_TYPE_2 0x2
+#define _T10_VPD83_NAA_TYPE_3 0x3
+#define _T10_VPD83_NAA_TYPE_5 0x5
+#define _T10_VPD83_NAA_TYPE_6 0x6
+
+#define _LSM_ERR_MSG_LEN 255
+
+#pragma pack(1)
+/*
+ * Table 589 — Device Identification VPD page
+ */
+struct t10_vpd83_header {
+ uint8_t dev_type : 5;
+ /* ^ PERIPHERAL DEVICE TYPE */
+ uint8_t qualifier : 3;
+ /* PERIPHERAL QUALIFIER */
+ uint8_t page_code;
+ uint8_t page_len_msb;
+ uint8_t page_len_lsb;
+};
+
+/*
+ * Table 590 — Designation descriptor
+ */
+struct t10_vpd83_id_header {
+ uint8_t code_set : 4;
+ uint8_t protocol_id : 4;
+ uint8_t designator_type : 4;
+ uint8_t association : 2;
+ uint8_t reserved_1 : 1;
+ uint8_t piv : 1;
+ uint8_t reserved_2;
+ uint8_t len;
+};
+
+struct t10_vpd83_naa_header {
+ uint8_t data_msb : 4;
+ uint8_t naa_type : 4;
+};
+
+#pragma pack()
+
+static char _lsm_err_msg[_LSM_ERR_MSG_LEN];
+
+#define _lsm_err_msg_clear() memset(_lsm_err_msg, 0, _LSM_ERR_MSG_LEN)
+
+#define _lsm_err_msg_set(format, ...) \
+ snprintf(_lsm_err_msg, _LSM_ERR_MSG_LEN, format, ##__VA_ARGS__)
+
+#define _lsm_string_list_foreach(l, i, d) \
+ for(i = 0; \
+ (l != NULL) && (i < lsm_string_list_size(l)) && \
+ (d = lsm_string_list_elem_get(l, i)); \
+ ++i)
+
+static void _be_raw_to_hex(uint8_t *raw, size_t len, char *out);
+static int _sysfs_vpd83_naa_of_sd_name(const char *sd_name, char **vpd83);
+
+/*
+ * Input big-endian uint8_t array, output has hex string.
+ * No check on output memory size or bundery, make sure before invoke.
+ */
+static void _be_raw_to_hex(uint8_t *raw, size_t len, char *out)
+{
+ size_t i = 0;
+
+ for (; i < len; ++i) {
+ snprintf(out + (i * 2), 3, "%02x", raw[i]);
+ }
+ out[len * 2] = 0;
+
+}
+
+static int _sysfs_read_file(const char *sys_fs_path, uint8_t *buff,
+ ssize_t *size, size_t max_size)
+{
+ int fd = -1;
+
+ *size = 0;
+ memset(buff, 0, max_size);
+
+ fd = open(sys_fs_path, O_RDONLY);
+ if (fd < 0) {
+ if (errno == ENOENT)
+ return LSM_ERR_NO_SUPPORT;
+
+ _lsm_err_msg_set("_sysfs_read_file(): Failed to open %s, error: %d, "
+ "%s\n", sys_fs_path, errno, strerror(errno));
+ return LSM_ERR_PLUGIN_BUG;
+ }
+ *size = read(fd, buff, max_size);
+ close(fd);
+
+ if (*size < 0) {
+ _lsm_err_msg_set("Failed to read %s, error: %d, %s\n", sys_fs_path,
+ errno, strerror(errno));
+ return LSM_ERR_PLUGIN_BUG;
+ }
+ return LSM_ERR_OK;
+}
+
+/*
+ * Parse /sys/block/sda/device/vpd_pg83 for VPD83 NAA ID.
+ * When no such sysfs file found, return LSM_ERR_NO_SUPPORT.
+ * When no NAA ID found, return LSM_ERR_OK and vpd83 as NULL.
+ * Return LSM_ERR_NO_MEMORY or LSM_ERR_NO_SUPPORT or LSM_ERR_PLUGIN_BUG
+ */
+static int _sysfs_vpd83_naa_of_sd_name(const char *sd_name, char **vpd83)
+{
+ char *sysfs_path = NULL;
+ ssize_t readed_size = 0;
+ uint8_t *end_p = NULL;
+ uint8_t *p = NULL;
+ struct t10_vpd83_header *vpd83_header = NULL;
+ uint32_t vpd83_len = 0;
+ struct t10_vpd83_id_header *id_header = NULL;
+ struct t10_vpd83_naa_header *naa_header = NULL;
+ int rc = LSM_ERR_OK;
+ uint8_t buff[_MAX_VPD83_LEN];
+ char vpd83_naa_id[_MAX_NAA_ID_LEN];
+
+ memset(vpd83_naa_id, 0, _MAX_NAA_ID_LEN);
+ *vpd83 = NULL;
+
+ if (sd_name == NULL) {
+ _lsm_err_msg_set("_sysfs_vpd83_naa_of_sd_name(): "
+ "Input sd_name argument is NULL");
+ rc = LSM_ERR_PLUGIN_BUG;
+ goto out;
+ }
+
+ sysfs_path = (char *) malloc(strlen("/sys/block//device/vpd_pg83") +
+ strlen(sd_name) + 1 /* trailing \0 */);
+ if (sysfs_path == NULL)
+ return LSM_ERR_NO_MEMORY;
+
+ sprintf(sysfs_path, "/sys/block/%s/device/vpd_pg83", sd_name);
+
+ rc = _sysfs_read_file(sysfs_path, buff, &readed_size, _MAX_VPD83_LEN);
+ free(sysfs_path);
+
+ if (rc != LSM_ERR_OK)
+ goto out;
+
+ /* Return NULL and LSM_ERR_OK when got invalid sysfs file */
+ /* Readed size is smaller than VPD83 header */
+ if (readed_size < sizeof(struct t10_vpd83_header))
+ goto out;
+
+ vpd83_header = (struct t10_vpd83_header*) buff;
+
+ /* Incorrect page code */
+ if (vpd83_header->page_code != _T10_VPD83_PAGE_CODE)
+ goto out;
+
+ vpd83_len = (((uint32_t) vpd83_header->page_len_msb) << 8) +
+ vpd83_header->page_len_lsb + sizeof(struct t10_vpd83_header);
+
+ end_p = buff + vpd83_len - 1;
+ p = buff + sizeof(struct t10_vpd83_header);
+
+ while(p <= end_p) {
+ /* Corrupted data: facing data end */
+ if (p + sizeof(struct t10_vpd83_id_header) > end_p)
+ goto out;
+
+ id_header = (struct t10_vpd83_id_header *) p;
+ /* Skip non-NAA ID */
+ if (id_header->designator_type != _T10_VPD83_DESIGNATOR_TYPE_NAA)
+ goto next_one;
+
+ naa_header = (struct t10_vpd83_naa_header *)
+ ((uint8_t *)id_header + sizeof(struct t10_vpd83_id_header));
+
+ switch(naa_header->naa_type) {
+ case _T10_VPD83_NAA_TYPE_2:
+ case _T10_VPD83_NAA_TYPE_3:
+ case _T10_VPD83_NAA_TYPE_5:
+ _be_raw_to_hex((uint8_t *) naa_header, _T10_VPD83_NAA_235_ID_LEN,
+ vpd83_naa_id);
+ break;
+ case _T10_VPD83_NAA_TYPE_6:
+ _be_raw_to_hex((uint8_t *) naa_header, _T10_VPD83_NAA_6_ID_LEN,
+ vpd83_naa_id);
+ break;
+ default:
+ /* Skip for Unknown NAA ID type */
+ goto next_one;
+ }
+ /* Quit when found first NAA ID */
+ if (vpd83_naa_id[0] != 0)
+ break;
+
+ next_one:
+ p = (uint8_t *) id_header + id_header->len +
+ sizeof(struct t10_vpd83_id_header);
+ continue;
+ }
+
+ if (vpd83_naa_id[0] == 0)
+ goto out;
+
+ *vpd83 = strdup(vpd83_naa_id);
+ if (*vpd83 == NULL)
+ return LSM_ERR_NO_MEMORY;
+
+ out:
+ return rc;
+}
+
+/*
+ * Try to parse /sys/block/sda/device/vpd_pg83 for VPD83 NAA ID frist.
+ * This sysfs file is missing in some older kenrel(like RHEL6), we use udev
+ * ID_WWN_WITH_EXTENSION property instead.
+ */
+static int _udev_vpd83_of_sd_name(const char *sd_name, char **vpd83)
+{
+ struct udev *udev = NULL;
+ struct udev_device *sd_udev = NULL;
+ int rc = LSM_ERR_OK;
+ char *sys_path = NULL;
+ const char *wwn = NULL;
+
+ *vpd83 = NULL;
+
+ sys_path = (char *) malloc(strlen("/sys/block/") + strlen(sd_name) +
+ 1 /* trailing \0 */);
+ if (sys_path == NULL)
+ return LSM_ERR_NO_MEMORY;
+
+ sprintf(sys_path, "/sys/block/%s", sd_name);
+
+ udev = udev_new();
+ if (udev == NULL) {
+ rc = LSM_ERR_NO_MEMORY;
+ goto out;
+ }
+
+ sd_udev = udev_device_new_from_syspath(udev, sys_path);
+ if (sd_udev == NULL) {
+ rc = LSM_ERR_NO_SUPPORT;
+ goto out;
+ }
+ wwn = udev_device_get_property_value(sd_udev, "ID_WWN_WITH_EXTENSION");
+ if (wwn == NULL)
+ goto out;
+
+ if (strncmp(wwn, "0x", strlen("0x")) == 0)
+ wwn += strlen("0x");
+
+ *vpd83 = strdup(wwn);
+ if (*vpd83 == NULL)
+ rc = LSM_ERR_NO_MEMORY;
+
+ out:
+ if (udev != NULL)
+ udev_unref(udev);
+
+ if (sd_udev != NULL)
+ udev_device_unref(sd_udev);
+
+ return rc;
+}
+
+static int _sysfs_get_all_sd_names(lsm_string_list **sd_name_list)
+{
+ DIR *dir = NULL;
+ struct dirent *dp = NULL;
+
+ *sd_name_list = lsm_string_list_alloc(0 /* no pre-allocation */);
+ if (*sd_name_list == NULL)
+ return LSM_ERR_NO_MEMORY;
+
+ dir = opendir(_SYS_BLOCK_PATH);
+ if (dir == NULL) {
+ lsm_string_list_free(*sd_name_list);
+ *sd_name_list = NULL;
+ _lsm_err_msg_set("Cannot optn %s", _SYS_BLOCK_PATH);
+ return LSM_ERR_PLUGIN_BUG;
+ }
+
+ do {
+ if ((dp = readdir(dir)) != NULL) {
+ if (strncmp(dp->d_name, "sd", strlen("sd")) != 0)
+ continue;
+ if (lsm_string_list_append(*sd_name_list, dp->d_name) != 0)
+ return LSM_ERR_NO_MEMORY;
+ }
+ } while(dp != NULL);
+
+ closedir(dir);
+
+ return LSM_ERR_OK;
+}
+
+int lsm_scsi_disk_paths_of_vpd83(const char *vpd83,
+ lsm_string_list **sd_path_list,
+ lsm_error **lsm_err)
+{
+ int rc = LSM_ERR_OK;
+ lsm_string_list *sd_name_list = NULL;
+ uint32_t i = 0;
+ const char *sd_name = NULL;
+ char *tmp_vpd83 = NULL;
+ char *sd_path = NULL;
+ bool sysfs_support = true;
+
+ _lsm_err_msg_clear();
+
+ if ((vpd83 == NULL) || (sd_path_list == NULL) || (lsm_err == NULL)) {
+ if (sd_path_list != NULL)
+ *sd_path_list = NULL;
+
+ if (lsm_err != NULL)
+ *lsm_err = NULL;
+
+ return LSM_ERR_INVALID_ARGUMENT;
+ }
+
+ *lsm_err = NULL;
+ *sd_path_list = lsm_string_list_alloc(0 /* no pre-allocation */);
+ if (*sd_path_list == NULL)
+ return LSM_ERR_NO_MEMORY;
+
+ rc = _sysfs_get_all_sd_names(&sd_name_list);
+ if (rc != LSM_ERR_OK)
+ goto out;
+
+ _lsm_string_list_foreach(sd_name_list, i, sd_name) {
+ if (sd_name == NULL)
+ continue;
+ if (sysfs_support == true) {
+ rc = _sysfs_vpd83_naa_of_sd_name(sd_name, &tmp_vpd83);
+ if (rc == LSM_ERR_NO_SUPPORT)
+ sysfs_support = false;
+ else if (rc != LSM_ERR_OK)
+ break;
+ }
+ /* Try udev way if got NO_SUPPORT from sysfs way. */
+ if (sysfs_support == false) {
+ rc = _udev_vpd83_of_sd_name(sd_name, &tmp_vpd83);
+ if (rc != LSM_ERR_OK)
+ break;
+ }
+ if (tmp_vpd83 == NULL)
+ continue;
+ if (strcmp(vpd83, tmp_vpd83) == 0) {
+ sd_path = (char *) malloc(strlen("/dev/") + strlen(sd_name) +
+ 1 /* trailing \0 */);
+ if (sd_path == NULL)
+ return LSM_ERR_NO_MEMORY;
+
+ sprintf(sd_path, "/dev/%s", sd_name);
+
+ if (lsm_string_list_append(*sd_path_list, sd_path) != 0)
+ return LSM_ERR_NO_MEMORY;
+ free(sd_path);
+ sd_path = NULL;
+ }
+ free(tmp_vpd83);
+ tmp_vpd83 = NULL;
+ }
+
+ out:
+ if (sd_name_list != NULL)
+ lsm_string_list_free(sd_name_list);
+
+ if (rc != LSM_ERR_OK) {
+ *lsm_err = LSM_ERROR_CREATE_PLUGIN_MSG(rc, _lsm_err_msg);
+
+ if (*sd_path_list != NULL)
+ lsm_string_list_free(*sd_path_list);
+
+ *sd_path_list = NULL;
+ }
+ return rc;
+}
diff --git a/configure.ac b/configure.ac
index beae390..908b3cd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -162,6 +162,7 @@ AM_PATH_PYTHON([2.6], [], AC_MSG_ERROR([Python interpreter 2.6 or 2.7 required])
AC_PYTHON_MODULE([pywbem], [Required])
AC_PYTHON_MODULE([M2Crypto], [Required])
AC_PYTHON_MODULE([argparse], [Required])
+PKG_CHECK_MODULES([LIBUDEV], [libudev])

dnl ==========================================================================
dnl Check for libmicrohttpd and json-c as it is needed for REST API daemon
--
1.8.3.1
Gris Ge
2015-11-17 07:30:27 UTC
Permalink
* New function lsm.SCSI.disk_paths_of_vpd83() to search all matching
SCSI disk paths(format: /dev/sd[a-z]+) for given VPD83 ID.

* This function is a wrap of C function lsm_scsi_disk_paths_of_vpd83().

* Updated lsmenv to support C extention (_scsi.so) of python.

Signed-off-by: Gris Ge <***@redhat.com>
---
configure.ac | 1 +
python_binding/Makefile.am | 9 ++++
python_binding/lsm/__init__.py | 3 ++
python_binding/lsm/_scsi.c | 110 +++++++++++++++++++++++++++++++++++++++++
tools/lsmenv | 4 ++
5 files changed, 127 insertions(+)
create mode 100644 python_binding/lsm/_scsi.c

diff --git a/configure.ac b/configure.ac
index 908b3cd..609e064 100644
--- a/configure.ac
+++ b/configure.ac
@@ -163,6 +163,7 @@ AC_PYTHON_MODULE([pywbem], [Required])
AC_PYTHON_MODULE([M2Crypto], [Required])
AC_PYTHON_MODULE([argparse], [Required])
PKG_CHECK_MODULES([LIBUDEV], [libudev])
+PKG_CHECK_MODULES([PYTHON2], [python2])

dnl ==========================================================================
dnl Check for libmicrohttpd and json-c as it is needed for REST API daemon
diff --git a/python_binding/Makefile.am b/python_binding/Makefile.am
index 8b0581a..b30d402 100644
--- a/python_binding/Makefile.am
+++ b/python_binding/Makefile.am
@@ -12,6 +12,15 @@ lsm_PYTHON = \
lsm/_iplugin.py \
lsm/_pluginrunner.py

+pyexec_LTLIBRARIES = lsm/_scsi.la
+pyexecdir = $(pythondir)/lsm
+
+lsm__scsi_la_CFLAGS = $(PYTHON2_CFLAGS) -I$(top_srcdir)/c_binding/include
+lsm__scsi_la_SOURCES = lsm/_scsi.c
+lsm__scsi_la_LDFLAGS = $(PYTHON2_LIBS) \
+ -module -avoid-version -export-symbols-regex init_scsi
+lsm__scsi_la_LIBADD = $(top_builddir)/c_binding/libstoragemgmt.la
+
external_PYTHON = \
lsm/external/__init__.py \
lsm/external/xmltodict.py
diff --git a/python_binding/lsm/__init__.py b/python_binding/lsm/__init__.py
index fb1cdbd..503d4ee 100644
--- a/python_binding/lsm/__init__.py
+++ b/python_binding/lsm/__init__.py
@@ -5,6 +5,9 @@
from _common import error, info, LsmError, ErrorNumber, \
JobStatus, uri_parse, md5, Proxy, size_bytes_2_size_human, \
common_urllib2_error_handler, size_human_2_size_bytes
+
+import lsm._scsi as SCSI
+
from _data import (Disk, Volume, Pool, System, FileSystem, FsSnapshot,
NfsExport, BlockRange, AccessGroup, TargetPort,
Capabilities)
diff --git a/python_binding/lsm/_scsi.c b/python_binding/lsm/_scsi.c
new file mode 100644
index 0000000..a0838f2
--- /dev/null
+++ b/python_binding/lsm/_scsi.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <***@redhat.com>
+ */
+
+#include <Python.h>
+#include <stdint.h>
+
+#include <libstoragemgmt/libstoragemgmt.h>
+
+static const char disk_paths_of_vpd83_docstring[] =
+ "Version:\n"
+ " 1.3\n"
+ "Usage:\n"
+ " Find out the /dev/sdX paths for given SCSI VPD page 0x83 NAA type\n"
+ " ID. Considering multipath, certain VPD83 will got multiple disks\n"
+ " associated.\n"
+ "Parameters:\n"
+ " vpd83 (string)\n"
+ " The VPD83 NAA type ID.\n"
+ "Returns:\n"
+ " sd_name (list of string)\n"
+ " Empty list is not found. The string format is '/dev/sd[a-z]+'.\n"
+ "\n"
+ "SpecialExceptions:\n"
+ " N/A\n"
+ "Capability:\n"
+ " N/A\n"
+ " No capability required from plugin as this is a library level\n"
+ " method.";
+
+static PyObject *disk_paths_of_vpd83(PyObject *self, PyObject *args,
+ PyObject *kwargs);
+
+/*
+ * TODO: Support METH_VARARGS | METH_KEYWORDS
+ */
+static PyMethodDef _scsi_methods[] = {
+ {"disk_paths_of_vpd83", (PyCFunction) disk_paths_of_vpd83,
+ METH_VARARGS | METH_KEYWORDS, disk_paths_of_vpd83_docstring},
+ {NULL, NULL, 0, NULL} /* Sentinel */
+};
+
+
+static PyObject *disk_paths_of_vpd83(PyObject *self, PyObject *args,
+ PyObject *kwargs)
+{
+ static const char *kwlist[] = {"vpd83", NULL};
+ const char *vpd83 = NULL;
+ PyObject *rc_list = NULL;
+ lsm_string_list *sd_path_list = NULL;
+ lsm_error *lsm_err = NULL;
+ int rc = LSM_ERR_OK;
+ uint8_t i = 0;
+ const char *sd_path = NULL;
+ PyObject *sd_path_obj = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", (char **) kwlist,
+ &vpd83))
+ return NULL;
+
+ if (vpd83 == NULL)
+ return NULL;
+
+ rc_list = PyList_New(0 /* No pre-allocation */);
+ if (rc_list == NULL)
+ return NULL;
+
+ rc = lsm_scsi_disk_paths_of_vpd83(vpd83, &sd_path_list, &lsm_err);
+ /* In python API defination, we don't raise error in function, only
+ * return empty list.
+ */
+ lsm_error_free(lsm_err);
+
+ if ((rc != LSM_ERR_OK) || (sd_path_list == NULL))
+ return rc_list;
+
+ for (; i < lsm_string_list_size(sd_path_list); ++i) {
+ sd_path = lsm_string_list_elem_get(sd_path_list, i);
+ if (sd_path == NULL)
+ continue;
+ sd_path_obj = PyString_FromString(sd_path);
+ if (sd_path_obj == NULL)
+ return NULL;
+ PyList_Append(rc_list, sd_path_obj);
+ /* ^ PyList_Append will increase the reference count of sd_path_obj */
+ Py_DECREF(sd_path_obj);
+ }
+ lsm_string_list_free(sd_path_list);
+
+ return rc_list;
+}
+
+PyMODINIT_FUNC init_scsi(void)
+{
+ (void) Py_InitModule("_scsi", _scsi_methods);
+}
diff --git a/tools/lsmenv b/tools/lsmenv
index 94055b6..f996d96 100755
--- a/tools/lsmenv
+++ b/tools/lsmenv
@@ -145,6 +145,10 @@ sub lsm_env_setup() {
system("mkdir -pv $LSM_UDS_PATH");
system("chown $LSM_USER $LSM_UDS_PATH");
}
+ unless ( -l "$py_lsm_dir/_scsi.so" ) {
+ print "INFO: Creating softlinke for _scsi.so\n";
+ system("ln -sv .libs/_scsi.so $py_lsm_dir/_scsi.so");
+ }

$ENV{LSM_UDS_PATH} = $LSM_UDS_PATH;
$ENV{PYTHONPATH} .= ":$py_binding_dir";
--
1.8.3.1
Gris Ge
2015-11-17 07:30:28 UTC
Permalink
* The `lsmcli list --type volumes` will include local scsi disks if VPD83
matches. Example:

$ lsmcli lv -s
--------------------------------
ID | VOL_ID_00001
Name | test
SCSI VPD 0x83 | 53333330000007d0
Block Size | 512
Block Count | 2097152
Size | 1073741824
Disabled | No
Pool ID | POOL_ID_00001
System ID | sim-01
Disk Paths | /dev/sda
| /dev/sdf
| /dev/sdh
| /dev/sdj
--------------------------------

Signed-off-by: Gris Ge <***@redhat.com>
---
tools/lsmcli/cmdline.py | 35 +++++++++++++++++++++++------------
tools/lsmcli/data_display.py | 1 +
2 files changed, 24 insertions(+), 12 deletions(-)

diff --git a/tools/lsmcli/cmdline.py b/tools/lsmcli/cmdline.py
index c66eaf2..0b81ced 100644
--- a/tools/lsmcli/cmdline.py
+++ b/tools/lsmcli/cmdline.py
@@ -34,7 +34,7 @@
from lsm import (Client, Pool, VERSION, LsmError, Disk,
Volume, JobStatus, ErrorNumber, BlockRange,
uri_parse, Proxy, size_human_2_size_bytes,
- AccessGroup, FileSystem, NfsExport, TargetPort)
+ AccessGroup, FileSystem, NfsExport, TargetPort, SCSI)

from lsm.lsmcli.data_display import (
DisplayData, PlugData, out,
@@ -904,20 +904,24 @@ def list(self, args):
search_value = args.tgt

if args.type == 'VOLUMES':
+ lsm_vols = []
if search_key == 'volume_id':
search_key = 'id'
if search_key == 'access_group_id':
lsm_ag = _get_item(self.c.access_groups(), args.ag,
"Access Group", raise_error=False)
if lsm_ag:
- return self.display_data(
- self.c.volumes_accessible_by_access_group(lsm_ag))
- else:
- return self.display_data([])
+ lsm_vols = self.c.volumes_accessible_by_access_group(
+ lsm_ag)
elif search_key and search_key not in Volume.SUPPORTED_SEARCH_KEYS:
raise ArgError("Search key '%s' is not supported by "
"volume listing." % search_key)
- self.display_data(self.c.volumes(search_key, search_value))
+ else:
+ lsm_vols = self.c.volumes(search_key, search_value)
+
+ self.display_data(
+ list(self._vol_add_sd_paths(v) for v in lsm_vols))
+
elif args.type == 'POOLS':
if search_key == 'pool_id':
search_key = 'id'
@@ -1023,7 +1027,7 @@ def access_group_volumes(self, args):
agl = self.c.access_groups()
group = _get_item(agl, args.ag, "Access Group")
vols = self.c.volumes_accessible_by_access_group(group)
- self.display_data(vols)
+ self.display_data(list(self._vol_add_sd_paths(v) for v in vols))

def iscsi_chap(self, args):
(init_id, init_type) = parse_convert_init(args.init)
@@ -1163,7 +1167,7 @@ def volume_create(self, args):
args.name,
self._size(args.size),
vol_provision_str_to_type(args.provisioning)))
- self.display_data([vol])
+ self.display_data([self._vol_add_sd_paths(vol)])

## Creates a snapshot
def fs_snap_create(self, args):
@@ -1271,7 +1275,7 @@ def volume_replicate(self, args):
vol = self._wait_for_it(
"replicate volume",
*self.c.volume_replicate(p, rep_type, v, args.name))
- self.display_data([vol])
+ self.display_data([self._vol_add_sd_paths(vol)])

## Replicates a range of a volume
def volume_replicate_range(self, args):
@@ -1324,7 +1328,7 @@ def volume_resize(self, args):
if self.confirm_prompt(False):
vol = self._wait_for_it("resize",
*self.c.volume_resize(v, size))
- self.display_data([vol])
+ self.display_data([self._vol_add_sd_paths(vol)])

## Enable a volume
def volume_enable(self, args):
@@ -1413,8 +1417,9 @@ def volume_raid_create(self, args):
strip_size = Volume.VCR_STRIP_SIZE_DEFAULT

self.display_data([
- self.c.volume_raid_create(
- args.name, raid_type, lsm_disks, strip_size)])
+ self._vol_add_sd_paths(
+ self.c.volume_raid_create(
+ args.name, raid_type, lsm_disks, strip_size))])

def volume_raid_create_cap(self, args):
lsm_sys = _get_item(self.c.systems(), args.sys, "System")
@@ -1536,3 +1541,9 @@ def process(self, cli=None):

self.args.func(self.args)
self.shutdown()
+
+ def _vol_add_sd_paths(self, lsm_vol):
+ lsm_vol.sd_paths = []
+ if len(lsm_vol.vpd83) > 0:
+ lsm_vol.sd_paths = SCSI.disk_paths_of_vpd83(lsm_vol.vpd83)
+ return lsm_vol
diff --git a/tools/lsmcli/data_display.py b/tools/lsmcli/data_display.py
index 2feda46..614d477 100644
--- a/tools/lsmcli/data_display.py
+++ b/tools/lsmcli/data_display.py
@@ -418,6 +418,7 @@ def __init__(self):
VOL_HEADER['admin_state'] = 'Disabled'
VOL_HEADER['pool_id'] = 'Pool ID'
VOL_HEADER['system_id'] = 'System ID'
+ VOL_HEADER['sd_paths'] = 'Disk Paths' # This is appended by cmdline.py

VOL_COLUMN_SKIP_KEYS = ['block_size', 'num_of_blocks']
--
1.8.3.1
Gris Ge
2015-11-17 07:30:29 UTC
Permalink
* Copy .libs/_scsi.so to test folder.

Signed-off-by: Gris Ge <***@redhat.com>
---
test/runtests.sh | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/test/runtests.sh b/test/runtests.sh
index 8b3c499..94949e0 100755
--- a/test/runtests.sh
+++ b/test/runtests.sh
@@ -90,6 +90,7 @@ bin_plugin=$rootdir/plugin/simc/.libs/
lsm_py_folder=$rootdir/python_binding
lsm_plugin_py_folder=$rootdir/plugin
lsmcli_py_folder=$rootdir/tools/lsmcli
+py_scsi_folder=$rootdir/python_binding/lsm/.libs/

if [ -e $rootdir/_build ]
then
@@ -97,6 +98,7 @@ then
LSMD_DAEMON=$rootdir/_build/daemon/lsmd
shared_libs=$rootdir/_build/c_binding/.libs/
bin_plugin=$rootdir/_build/plugin/simc/.libs/
+ py_scsi_folder=$rootdir/_build/python_binding/lsm/.libs/
# In distcheck, all folder is read only(except _build and _inst).
# which prevent us from linking plugin and lsmcli into python/lsm folder.
chmod +w $rootdir/python_binding/lsm
@@ -144,6 +146,9 @@ if [ -e "$PYTHONPATH/lsm/lsmcli" ] || [ -L "$PYTHONPATH/lsm/lsmcli" ];then
fi
good "cp -av $lsmcli_py_folder $PYTHONPATH/lsm/"

+#Copy Python shared library _scsi.so
+good "cp -av $py_scsi_folder/*.so* $PYTHONPATH/lsm/"
+
#Copy plugins to one directory.
good "find $rootdir/ \( ! -regex '.*/\..*' \) -type f -name \*_lsmplugin -exec cp {} $plugins \;"
--
1.8.3.1
Gris Ge
2015-11-17 07:30:30 UTC
Permalink
* Test LSM_ERR_INVALID_ARGUMENT of lsm_scsi_disk_paths_of_vpd83().
* Test dangling pointer of 'sd_path_list' output pointer.

Signed-off-by: Gris Ge <***@redhat.com>
---
test/tester.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 65 insertions(+)

diff --git a/test/tester.c b/test/tester.c
index da2a3a4..7ccd2c8 100644
--- a/test/tester.c
+++ b/test/tester.c
@@ -36,6 +36,7 @@ const char *ISCSI_HOST[2] = { "iqn.1994-05.com.domain:01.89bd01",
static int which_plugin = 0;

#define POLL_SLEEP 50000
+#define VPD83_TO_SEARCH "600508b1001c79ade5178f0626caaa9c"

lsm_connect *c = NULL;

@@ -3083,6 +3084,69 @@ START_TEST(test_volume_raid_create)
}
END_TEST

+
+/*
+ * Just check whether LSM_ERR_INVALID_ARGUMENT handle correctly.
+ */
+START_TEST(test_scsi_disk_paths_of_vpd83)
+{
+ int rc = LSM_ERR_OK;
+ lsm_string_list *sd_path_list;
+ /* Not initialized in order to test dangling pointer sd_path_list */
+ lsm_error *lsm_err;
+ /* Not initialized in order to test dangling pointer lsm_err */
+
+ if (which_plugin == 1){
+ /* silently skip on simc, no need for duplicate test. */
+ return;
+ }
+
+ rc = lsm_scsi_disk_paths_of_vpd83(NULL, &sd_path_list, &lsm_err);
+ fail_unless(rc == LSM_ERR_INVALID_ARGUMENT,
+ "lsm_scsi_disk_paths_of_vpd83(): Expecting "
+ "LSM_ERR_INVALID_ARGUMENT when vpd83 argument pointer is NULL");
+
+ fail_unless(sd_path_list == NULL,
+ "lsm_scsi_disk_paths_of_vpd83(): Expecting "
+ "sd_path_list been set as NULL.");
+
+ fail_unless(lsm_err == NULL,
+ "lsm_scsi_disk_paths_of_vpd83(): Expecting "
+ "lsm_err been set as NULL.");
+
+ rc = lsm_scsi_disk_paths_of_vpd83(VPD83_TO_SEARCH, NULL, &lsm_err);
+ fail_unless(rc == LSM_ERR_INVALID_ARGUMENT,
+ "lsm_scsi_disk_paths_of_vpd83(): Expecting "
+ "LSM_ERR_INVALID_ARGUMENT when sd_path_list argument pointer "
+ "is NULL");
+
+ rc = lsm_scsi_disk_paths_of_vpd83(VPD83_TO_SEARCH, &sd_path_list, NULL);
+ fail_unless(rc == LSM_ERR_INVALID_ARGUMENT,
+ "lsm_scsi_disk_paths_of_vpd83(): Expecting "
+ "LSM_ERR_INVALID_ARGUMENT when lsm_err argument pointer "
+ "is NULL");
+
+ rc = lsm_scsi_disk_paths_of_vpd83(VPD83_TO_SEARCH, &sd_path_list, &lsm_err);
+ fail_unless(rc == LSM_ERR_OK,
+ "lsm_scsi_disk_paths_of_vpd83(): Expecting LSM_ERR_OK"
+ "when no argument is NULL");
+
+ fail_unless(lsm_err == NULL,
+ "lsm_scsi_disk_paths_of_vpd83(): Expecting lsm_err as NULL"
+ "when no argument is NULL");
+
+ if (sd_path_list != NULL)
+ lsm_string_list_free(sd_path_list);
+
+ if (lsm_err != NULL)
+ lsm_error_free(lsm_err);
+ /* ^ No need to free lsm_err as programme already quit due to above check,
+ * keeping this line is just for code demonstration.
+ */
+}
+END_TEST
+
+
Suite * lsm_suite(void)
{
Suite *s = suite_create("libStorageMgmt");
@@ -3124,6 +3188,7 @@ Suite * lsm_suite(void)
tcase_add_test(basic, test_pool_member_info);
tcase_add_test(basic, test_volume_raid_create_cap_get);
tcase_add_test(basic, test_volume_raid_create);
+ tcase_add_test(basic, test_scsi_disk_paths_of_vpd83);

suite_add_tcase(s, basic);
return s;
--
1.8.3.1
Gris Ge
2015-11-17 07:30:31 UTC
Permalink
* Add the new python_binding/lsm/_scsi.so file.
* Add build require for libudev and python-devel.
* Remove noarch type of libstoragemgmt-python package.

Signed-off-by: Gris Ge <***@redhat.com>
---
packaging/libstoragemgmt.spec.in | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/packaging/libstoragemgmt.spec.in b/packaging/libstoragemgmt.spec.in
index 00da8c8..f1dba06 100644
--- a/packaging/libstoragemgmt.spec.in
+++ b/packaging/libstoragemgmt.spec.in
@@ -70,6 +70,13 @@ BuildRequires: libyajl-devel
BuildRequires: yajl-devel
%endif

+%if 0%{?rhel} == 6
+BuildRequires: libudev-devel
+%else
+BuildRequires: systemd-devel
+%endif
+BuildRequires: python-devel
+
%if 0%{?do_fdupes}
BuildRequires: fdupes
%endif
@@ -122,7 +129,6 @@ developing applications that use %{name}.
Summary: Python client libraries and plug-in support for %{libstoragemgmt}
Group: System Environment/Libraries
Requires: %{libstoragemgmt} = %{version}-%{release}
-BuildArch: noarch
Requires: python-argparse
%if 0%{?rhel} == 6
# No way to detect 6.2 yet. Just forcing all RHEL 6 to install
@@ -540,6 +546,7 @@ fi
%{python_sitelib}/lsm/external/*
%{python_sitelib}/lsm/_client.*
%{python_sitelib}/lsm/_common.*
+%{python_sitelib}/lsm/_scsi.*
%{python_sitelib}/lsm/_data.*
%{python_sitelib}/lsm/_iplugin.*
%{python_sitelib}/lsm/_pluginrunner.*
--
1.8.3.1
Gris Ge
2015-11-17 07:30:32 UTC
Permalink
* Just allow python absolute import like:
from lsm._scsi import SCSI

Signed-off-by: Gris Ge <***@redhat.com>
---
tools/utility/check_const.pl | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/tools/utility/check_const.pl b/tools/utility/check_const.pl
index 64abf34..2b2eead 100644
--- a/tools/utility/check_const.pl
+++ b/tools/utility/check_const.pl
@@ -267,7 +267,14 @@ sub _parse_py_init_file($) {

foreach my $line (@lines) {
if ( $line =~ /from ([^ ]+) import (.+)$/ ) {
- push @rc1, sprintf "%s/%s.py", $folder_path, $1;
+ my $module_file_name = $1;
+ if ($module_file_name =~ /^lsm\.(.+)$/) {
+ $module_file_name = $1;
+ $module_file_name =~ s|\.|/|g;
+ push @rc1, sprintf "%s/%s.py", $folder_path, $module_file_name;
+ } else {
+ push @rc1, sprintf "%s/%s.py", $folder_path, $module_file_name;
+ }
my $class_line = $2;
while ( $class_line =~ /([A-Z][a-zA-Z]+)[, \\]*/g ) {
push @rc2, $1;
--
1.8.3.1
Gris Ge
2015-11-17 07:30:33 UTC
Permalink
* New "Disk Name" column added to volume listing, which cause list[-2]
does not pointing to pool id, changed it to index number 5.

Signed-off-by: Gris Ge <***@redhat.com>
---
test/cmdtest.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/cmdtest.py b/test/cmdtest.py
index 7fa6599..bbf39a4 100755
--- a/test/cmdtest.py
+++ b/test/cmdtest.py
@@ -750,7 +750,7 @@ def volume_raid_create_test(cap, system_id):

volume = parse(out)
vol_id = volume[0][0]
- pool_id = volume[0][-2]
+ pool_id = volume[0][5]

if cap['VOLUME_RAID_INFO']:
out = call(
--
1.8.3.1
Gris Ge
2015-11-17 07:30:34 UTC
Permalink
* Use random generated volume name for volume_raid_create_test() test.

Signed-off-by: Gris Ge <***@redhat.com>
---
test/cmdtest.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/test/cmdtest.py b/test/cmdtest.py
index bbf39a4..22ee372 100755
--- a/test/cmdtest.py
+++ b/test/cmdtest.py
@@ -745,7 +745,8 @@ def volume_raid_create_test(cap, system_id):

out = call([
cmd, '-t' + sep, 'volume-raid-create', '--disk', free_disk_ids[0],
- '--disk', free_disk_ids[1], '--name', 'test_volume_raid_create',
+ '--disk', free_disk_ids[1], '--name',
+ 'test_volume_raid_create_%s' % rs(4),
'--raid-type', 'raid1'])[1]

volume = parse(out)
--
1.8.3.1
Gris Ge
2015-11-17 07:30:35 UTC
Permalink
* New these packages for libudev and pyudev:
* python-dev
* libudev-dev

Signed-off-by: Gris Ge <***@redhat.com>
---
.travis.yml | 2 ++
1 file changed, 2 insertions(+)

diff --git a/.travis.yml b/.travis.yml
index f267aed..25800e0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -19,6 +19,8 @@ addons:
- python-m2crypto
- libssl-dev
- libconfig-dev
+ - libudev-dev
+ - python-dev

compiler: gcc
--
1.8.3.1
Gris Ge
2015-11-17 07:30:36 UTC
Permalink
* In distcheck, all code folder has not write permission which
cause clean up method cannot remove python modules in /tmp folder.
Error message:

rm: cannot remove `/tmp/9472/python/lsm/external/__init__.py': Permission
denied

* Fixed by add writing permission to /tmp/<random> folder recursively before
removal.

Signed-off-by: Gris Ge <***@redhat.com>
---
test/runtests.sh | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/test/runtests.sh b/test/runtests.sh
index 94949e0..bf3f95f 100755
--- a/test/runtests.sh
+++ b/test/runtests.sh
@@ -45,15 +45,9 @@ cleanup() {
cat $LSMD_TMP_LOG_FILE
if [ -e $LSM_UDS_PATH ]
then
+ chmod +w -R $base
rm -rf $base
fi
-
- if [ -e $rootdir/_build ]
- then
- rm $lsm_py_folder/lsm/plugin
- rm $lsm_py_folder/lsm/lsmcli
- chmod -w $lsm_py_folder/lsm
- fi
}

good() {
--
1.8.3.1
Gris Ge
2015-11-19 08:22:49 UTC
Permalink
* API for querying scsi disk paths from VPD83 ID.
C:
int lsm_scsi_disk_paths_of_vpd83(const char *vpd83,
lsm_string_list **sd_path_list,
lsm_error **lsm_err)

Python:
lsm.SCSI.disk_paths_of_vpd83(vpd83)

* lsmcli changes: add "Disk Paths", example:

lsmcli lv -s
--------------------------------
ID | VOL_ID_00001
Name | lsm_RDIQVLWJYZKK
SCSI VPD 0x83 | 53333330000007d0
Block Size | 512
Block Count | 61440
Size | 31457280
Disabled | No
Pool ID | POOL_ID_00004
System ID | sim-01
Disk Paths | /dev/sdb
| /dev/sdd
| /dev/sdf
| /dev/sdh
--------------------------------

Github pull request is:
https://github.com/libstorage/libstoragemgmt/pull/71

Changes in V2:

* API name changed to lsm_scsi_disk_paths_of_vpd83() and
lsm.SCSI.disk_paths_of_vpd83().
* Fixed dangling pointer of sd_path_list.
* Add test for dangling pointer of sd_path_list.
* Changed lsmcli output name as Disk Paths.

Changes in V3:

* Add 'lsm_error ** lsm_err' argument to received error message.
* Try sysfs vpd83 file fist, if not support, use udev.
* Change python module to C extension of C API.

Changes in V4:
* Fix autotool for RHEL 6 which does not ship pkgconfig file for
python2-devel.

Gris Ge (11):
C API: New function for SCSI disk path matching.
Python API: New function for SCSI disk path matching.
lsmcli: Add SCSI disk paths in output of volume listing.
Test: Fix missing lsm.SCSI module.
C unit test: Test case for lsm_scsi_disk_paths_of_vpd83()
RPM SPEC: Add new python library file.
Constant check: Support python absolute import.
lsmcli test: Fix failed test case caused by new disk name colume.
lsmcli test: Fix test case volume_raid_create_test()
Travis CI: Add new compile dependency.
Test: Fix incorrect clean up for distcheck.

.travis.yml | 2 +
c_binding/Makefile.am | 8 +-
c_binding/include/libstoragemgmt/Makefile.am | 1 +
c_binding/include/libstoragemgmt/libstoragemgmt.h | 1 +
.../include/libstoragemgmt/libstoragemgmt_scsi.h | 55 +++
c_binding/lsm_scsi.c | 419 +++++++++++++++++++++
configure.ac | 13 +
packaging/libstoragemgmt.spec.in | 9 +-
python_binding/Makefile.am | 9 +
python_binding/lsm/__init__.py | 3 +
python_binding/lsm/_scsi.c | 110 ++++++
test/cmdtest.py | 5 +-
test/runtests.sh | 13 +-
test/tester.c | 65 ++++
tools/lsmcli/cmdline.py | 35 +-
tools/lsmcli/data_display.py | 1 +
tools/lsmenv | 4 +
tools/utility/check_const.pl | 9 +-
18 files changed, 736 insertions(+), 26 deletions(-)
create mode 100644 c_binding/include/libstoragemgmt/libstoragemgmt_scsi.h
create mode 100644 c_binding/lsm_scsi.c
create mode 100644 python_binding/lsm/_scsi.c
--
1.8.3.1
Gris Ge
2015-11-19 08:22:50 UTC
Permalink
* New method lsm_scsi_disk_paths_of_vpd83() takes VPD83 ID to find out
all matching scsi disk paths(format:/dev/sd[a-z]+).

Signed-off-by: Gris Ge <***@redhat.com>
---
c_binding/Makefile.am | 8 +-
c_binding/include/libstoragemgmt/Makefile.am | 1 +
c_binding/include/libstoragemgmt/libstoragemgmt.h | 1 +
.../include/libstoragemgmt/libstoragemgmt_scsi.h | 55 +++
c_binding/lsm_scsi.c | 419 +++++++++++++++++++++
configure.ac | 1 +
6 files changed, 482 insertions(+), 3 deletions(-)
create mode 100644 c_binding/include/libstoragemgmt/libstoragemgmt_scsi.h
create mode 100644 c_binding/lsm_scsi.c

diff --git a/c_binding/Makefile.am b/c_binding/Makefile.am
index e4b8e1b..18da493 100644
--- a/c_binding/Makefile.am
+++ b/c_binding/Makefile.am
@@ -3,13 +3,15 @@ SUBDIRS = include
AM_CPPFLAGS = -I$(top_srcdir)/c_binding/include \
-I$(top_builddir)/c_binding/include \
-***@srcdir@/c_binding/include \
- $(LIBXML_CFLAGS) $(LIBGLIB_CFLAGS)
+ $(LIBXML_CFLAGS) $(LIBGLIB_CFLAGS) \
+ $(LIBUDEV_CFLAGS)

lib_LTLIBRARIES = libstoragemgmt.la

-libstoragemgmt_la_LIBADD=$(LIBXML_LIBS) $(YAJL_LIBS) $(LIBGLIB_LIBS)
+libstoragemgmt_la_LIBADD=$(LIBXML_LIBS) $(YAJL_LIBS) $(LIBGLIB_LIBS) \
+ $(LIBUDEV_LIBS)
libstoragemgmt_la_LDFLAGS= -version-info $(LIBSM_LIBTOOL_VERSION)
libstoragemgmt_la_SOURCES= \
lsm_mgmt.cpp lsm_datatypes.hpp lsm_datatypes.cpp lsm_convert.hpp \
lsm_convert.cpp lsm_ipc.hpp lsm_ipc.cpp lsm_plugin_ipc.hpp \
- lsm_plugin_ipc.cpp util/qparams.c util/qparams.h
+ lsm_plugin_ipc.cpp util/qparams.c util/qparams.h lsm_scsi.c
diff --git a/c_binding/include/libstoragemgmt/Makefile.am b/c_binding/include/libstoragemgmt/Makefile.am
index 2a947f6..f7b8dbd 100644
--- a/c_binding/include/libstoragemgmt/Makefile.am
+++ b/c_binding/include/libstoragemgmt/Makefile.am
@@ -23,6 +23,7 @@ lsminc_HEADERS = \
libstoragemgmt_targetport.h \
libstoragemgmt_types.h \
libstoragemgmt_version.h \
+ libstoragemgmt_scsi.h \
libstoragemgmt_volumes.h


diff --git a/c_binding/include/libstoragemgmt/libstoragemgmt.h b/c_binding/include/libstoragemgmt/libstoragemgmt.h
index b902bd8..8450434 100644
--- a/c_binding/include/libstoragemgmt/libstoragemgmt.h
+++ b/c_binding/include/libstoragemgmt/libstoragemgmt.h
@@ -34,6 +34,7 @@
#include "libstoragemgmt_systems.h"
#include "libstoragemgmt_targetport.h"
#include "libstoragemgmt_volumes.h"
+#include "libstoragemgmt_scsi.h"


/*! \mainpage libStorageMgmt
diff --git a/c_binding/include/libstoragemgmt/libstoragemgmt_scsi.h b/c_binding/include/libstoragemgmt/libstoragemgmt_scsi.h
new file mode 100644
index 0000000..a229692
--- /dev/null
+++ b/c_binding/include/libstoragemgmt/libstoragemgmt_scsi.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <***@redhat.com>
+ *
+ */
+
+#ifndef LIBSTORAGEMGMT_SCSI_H
+#define LIBSTORAGEMGMT_SCSI_H
+
+#include "libstoragemgmt_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Find out the scsi disk paths of given SCSI VPD page 0x83 NAA ID.
+ * New in version 1.3.
+ * @param[in] vpd83 String. The VPD83 ID retrieved from LSM volume or disk.
+ * for supported strip sizes.
+ * @param[out] sd_path_list
+ * Output pointer of lsm_string_list. The format of scsi
+ * disk path will be "/dev/sd[a-z]+".
+ * NULL if no found or got error.
+ * Memory should be freed by lsm_string_list_free().
+ * @param[out] lsm_err
+ * Output pointer of lsm_error. Error message could be
+ * retrived via lsm_error_message_get(). Memory should be
+ * freed by lsm_error_free().
+ * @return LSM_ERR_OK on success.
+ * LSM_ERR_INVALID_ARGUMENT when any argument is NULL.
+ * LSM_ERR_NO_MEMORY when no memory.
+ * LSM_ERR_LIB_BUG when something unexpected happens.
+ */
+int LSM_DLL_EXPORT lsm_scsi_disk_paths_of_vpd83(const char *vpd83,
+ lsm_string_list **sd_path_list,
+ lsm_error **lsm_err);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* LIBSTORAGEMGMT_SCSI_H */
diff --git a/c_binding/lsm_scsi.c b/c_binding/lsm_scsi.c
new file mode 100644
index 0000000..a488f48
--- /dev/null
+++ b/c_binding/lsm_scsi.c
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <***@redhat.com>
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <libudev.h>
+#include <stdbool.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "libstoragemgmt/libstoragemgmt.h"
+#include "libstoragemgmt/libstoragemgmt_error.h"
+#include "libstoragemgmt/libstoragemgmt_plug_interface.h"
+
+#define _MAX_VPD83_LEN 0xff + 4
+#define _MAX_NAA_ID_LEN 33 /* Max one is 6h IEEE Registered Extended ID */
+#define _SYS_BLOCK_PATH "/sys/block"
+
+#define _T10_VPD83_NAA_235_ID_LEN 8
+#define _T10_VPD83_NAA_6_ID_LEN 16
+#define _T10_VPD83_PAGE_CODE 0x83
+#define _T10_VPD83_DESIGNATOR_TYPE_NAA 0x3
+#define _T10_VPD83_NAA_TYPE_2 0x2
+#define _T10_VPD83_NAA_TYPE_3 0x3
+#define _T10_VPD83_NAA_TYPE_5 0x5
+#define _T10_VPD83_NAA_TYPE_6 0x6
+
+#define _LSM_ERR_MSG_LEN 255
+
+#pragma pack(1)
+/*
+ * Table 589 — Device Identification VPD page
+ */
+struct t10_vpd83_header {
+ uint8_t dev_type : 5;
+ /* ^ PERIPHERAL DEVICE TYPE */
+ uint8_t qualifier : 3;
+ /* PERIPHERAL QUALIFIER */
+ uint8_t page_code;
+ uint8_t page_len_msb;
+ uint8_t page_len_lsb;
+};
+
+/*
+ * Table 590 — Designation descriptor
+ */
+struct t10_vpd83_id_header {
+ uint8_t code_set : 4;
+ uint8_t protocol_id : 4;
+ uint8_t designator_type : 4;
+ uint8_t association : 2;
+ uint8_t reserved_1 : 1;
+ uint8_t piv : 1;
+ uint8_t reserved_2;
+ uint8_t len;
+};
+
+struct t10_vpd83_naa_header {
+ uint8_t data_msb : 4;
+ uint8_t naa_type : 4;
+};
+
+#pragma pack()
+
+static char _lsm_err_msg[_LSM_ERR_MSG_LEN];
+
+#define _lsm_err_msg_clear() memset(_lsm_err_msg, 0, _LSM_ERR_MSG_LEN)
+
+#define _lsm_err_msg_set(format, ...) \
+ snprintf(_lsm_err_msg, _LSM_ERR_MSG_LEN, format, ##__VA_ARGS__)
+
+#define _lsm_string_list_foreach(l, i, d) \
+ for(i = 0; \
+ (l != NULL) && (i < lsm_string_list_size(l)) && \
+ (d = lsm_string_list_elem_get(l, i)); \
+ ++i)
+
+static void _be_raw_to_hex(uint8_t *raw, size_t len, char *out);
+static int _sysfs_vpd83_naa_of_sd_name(const char *sd_name, char **vpd83);
+
+/*
+ * Input big-endian uint8_t array, output has hex string.
+ * No check on output memory size or bundery, make sure before invoke.
+ */
+static void _be_raw_to_hex(uint8_t *raw, size_t len, char *out)
+{
+ size_t i = 0;
+
+ for (; i < len; ++i) {
+ snprintf(out + (i * 2), 3, "%02x", raw[i]);
+ }
+ out[len * 2] = 0;
+
+}
+
+static int _sysfs_read_file(const char *sys_fs_path, uint8_t *buff,
+ ssize_t *size, size_t max_size)
+{
+ int fd = -1;
+
+ *size = 0;
+ memset(buff, 0, max_size);
+
+ fd = open(sys_fs_path, O_RDONLY);
+ if (fd < 0) {
+ if (errno == ENOENT)
+ return LSM_ERR_NO_SUPPORT;
+
+ _lsm_err_msg_set("_sysfs_read_file(): Failed to open %s, error: %d, "
+ "%s\n", sys_fs_path, errno, strerror(errno));
+ return LSM_ERR_PLUGIN_BUG;
+ }
+ *size = read(fd, buff, max_size);
+ close(fd);
+
+ if (*size < 0) {
+ _lsm_err_msg_set("Failed to read %s, error: %d, %s\n", sys_fs_path,
+ errno, strerror(errno));
+ return LSM_ERR_PLUGIN_BUG;
+ }
+ return LSM_ERR_OK;
+}
+
+/*
+ * Parse /sys/block/sda/device/vpd_pg83 for VPD83 NAA ID.
+ * When no such sysfs file found, return LSM_ERR_NO_SUPPORT.
+ * When no NAA ID found, return LSM_ERR_OK and vpd83 as NULL.
+ * Return LSM_ERR_NO_MEMORY or LSM_ERR_NO_SUPPORT or LSM_ERR_PLUGIN_BUG
+ */
+static int _sysfs_vpd83_naa_of_sd_name(const char *sd_name, char **vpd83)
+{
+ char *sysfs_path = NULL;
+ ssize_t readed_size = 0;
+ uint8_t *end_p = NULL;
+ uint8_t *p = NULL;
+ struct t10_vpd83_header *vpd83_header = NULL;
+ uint32_t vpd83_len = 0;
+ struct t10_vpd83_id_header *id_header = NULL;
+ struct t10_vpd83_naa_header *naa_header = NULL;
+ int rc = LSM_ERR_OK;
+ uint8_t buff[_MAX_VPD83_LEN];
+ char vpd83_naa_id[_MAX_NAA_ID_LEN];
+
+ memset(vpd83_naa_id, 0, _MAX_NAA_ID_LEN);
+ *vpd83 = NULL;
+
+ if (sd_name == NULL) {
+ _lsm_err_msg_set("_sysfs_vpd83_naa_of_sd_name(): "
+ "Input sd_name argument is NULL");
+ rc = LSM_ERR_PLUGIN_BUG;
+ goto out;
+ }
+
+ sysfs_path = (char *) malloc(strlen("/sys/block//device/vpd_pg83") +
+ strlen(sd_name) + 1 /* trailing \0 */);
+ if (sysfs_path == NULL)
+ return LSM_ERR_NO_MEMORY;
+
+ sprintf(sysfs_path, "/sys/block/%s/device/vpd_pg83", sd_name);
+
+ rc = _sysfs_read_file(sysfs_path, buff, &readed_size, _MAX_VPD83_LEN);
+ free(sysfs_path);
+
+ if (rc != LSM_ERR_OK)
+ goto out;
+
+ /* Return NULL and LSM_ERR_OK when got invalid sysfs file */
+ /* Readed size is smaller than VPD83 header */
+ if (readed_size < sizeof(struct t10_vpd83_header))
+ goto out;
+
+ vpd83_header = (struct t10_vpd83_header*) buff;
+
+ /* Incorrect page code */
+ if (vpd83_header->page_code != _T10_VPD83_PAGE_CODE)
+ goto out;
+
+ vpd83_len = (((uint32_t) vpd83_header->page_len_msb) << 8) +
+ vpd83_header->page_len_lsb + sizeof(struct t10_vpd83_header);
+
+ end_p = buff + vpd83_len - 1;
+ p = buff + sizeof(struct t10_vpd83_header);
+
+ while(p <= end_p) {
+ /* Corrupted data: facing data end */
+ if (p + sizeof(struct t10_vpd83_id_header) > end_p)
+ goto out;
+
+ id_header = (struct t10_vpd83_id_header *) p;
+ /* Skip non-NAA ID */
+ if (id_header->designator_type != _T10_VPD83_DESIGNATOR_TYPE_NAA)
+ goto next_one;
+
+ naa_header = (struct t10_vpd83_naa_header *)
+ ((uint8_t *)id_header + sizeof(struct t10_vpd83_id_header));
+
+ switch(naa_header->naa_type) {
+ case _T10_VPD83_NAA_TYPE_2:
+ case _T10_VPD83_NAA_TYPE_3:
+ case _T10_VPD83_NAA_TYPE_5:
+ _be_raw_to_hex((uint8_t *) naa_header, _T10_VPD83_NAA_235_ID_LEN,
+ vpd83_naa_id);
+ break;
+ case _T10_VPD83_NAA_TYPE_6:
+ _be_raw_to_hex((uint8_t *) naa_header, _T10_VPD83_NAA_6_ID_LEN,
+ vpd83_naa_id);
+ break;
+ default:
+ /* Skip for Unknown NAA ID type */
+ goto next_one;
+ }
+ /* Quit when found first NAA ID */
+ if (vpd83_naa_id[0] != 0)
+ break;
+
+ next_one:
+ p = (uint8_t *) id_header + id_header->len +
+ sizeof(struct t10_vpd83_id_header);
+ continue;
+ }
+
+ if (vpd83_naa_id[0] == 0)
+ goto out;
+
+ *vpd83 = strdup(vpd83_naa_id);
+ if (*vpd83 == NULL)
+ return LSM_ERR_NO_MEMORY;
+
+ out:
+ return rc;
+}
+
+/*
+ * Try to parse /sys/block/sda/device/vpd_pg83 for VPD83 NAA ID frist.
+ * This sysfs file is missing in some older kenrel(like RHEL6), we use udev
+ * ID_WWN_WITH_EXTENSION property instead.
+ */
+static int _udev_vpd83_of_sd_name(const char *sd_name, char **vpd83)
+{
+ struct udev *udev = NULL;
+ struct udev_device *sd_udev = NULL;
+ int rc = LSM_ERR_OK;
+ char *sys_path = NULL;
+ const char *wwn = NULL;
+
+ *vpd83 = NULL;
+
+ sys_path = (char *) malloc(strlen("/sys/block/") + strlen(sd_name) +
+ 1 /* trailing \0 */);
+ if (sys_path == NULL)
+ return LSM_ERR_NO_MEMORY;
+
+ sprintf(sys_path, "/sys/block/%s", sd_name);
+
+ udev = udev_new();
+ if (udev == NULL) {
+ rc = LSM_ERR_NO_MEMORY;
+ goto out;
+ }
+
+ sd_udev = udev_device_new_from_syspath(udev, sys_path);
+ if (sd_udev == NULL) {
+ rc = LSM_ERR_NO_SUPPORT;
+ goto out;
+ }
+ wwn = udev_device_get_property_value(sd_udev, "ID_WWN_WITH_EXTENSION");
+ if (wwn == NULL)
+ goto out;
+
+ if (strncmp(wwn, "0x", strlen("0x")) == 0)
+ wwn += strlen("0x");
+
+ *vpd83 = strdup(wwn);
+ if (*vpd83 == NULL)
+ rc = LSM_ERR_NO_MEMORY;
+
+ out:
+ if (udev != NULL)
+ udev_unref(udev);
+
+ if (sd_udev != NULL)
+ udev_device_unref(sd_udev);
+
+ return rc;
+}
+
+static int _sysfs_get_all_sd_names(lsm_string_list **sd_name_list)
+{
+ DIR *dir = NULL;
+ struct dirent *dp = NULL;
+
+ *sd_name_list = lsm_string_list_alloc(0 /* no pre-allocation */);
+ if (*sd_name_list == NULL)
+ return LSM_ERR_NO_MEMORY;
+
+ dir = opendir(_SYS_BLOCK_PATH);
+ if (dir == NULL) {
+ lsm_string_list_free(*sd_name_list);
+ *sd_name_list = NULL;
+ _lsm_err_msg_set("Cannot optn %s", _SYS_BLOCK_PATH);
+ return LSM_ERR_PLUGIN_BUG;
+ }
+
+ do {
+ if ((dp = readdir(dir)) != NULL) {
+ if (strncmp(dp->d_name, "sd", strlen("sd")) != 0)
+ continue;
+ if (lsm_string_list_append(*sd_name_list, dp->d_name) != 0)
+ return LSM_ERR_NO_MEMORY;
+ }
+ } while(dp != NULL);
+
+ closedir(dir);
+
+ return LSM_ERR_OK;
+}
+
+int lsm_scsi_disk_paths_of_vpd83(const char *vpd83,
+ lsm_string_list **sd_path_list,
+ lsm_error **lsm_err)
+{
+ int rc = LSM_ERR_OK;
+ lsm_string_list *sd_name_list = NULL;
+ uint32_t i = 0;
+ const char *sd_name = NULL;
+ char *tmp_vpd83 = NULL;
+ char *sd_path = NULL;
+ bool sysfs_support = true;
+
+ _lsm_err_msg_clear();
+
+ if ((vpd83 == NULL) || (sd_path_list == NULL) || (lsm_err == NULL)) {
+ if (sd_path_list != NULL)
+ *sd_path_list = NULL;
+
+ if (lsm_err != NULL)
+ *lsm_err = NULL;
+
+ return LSM_ERR_INVALID_ARGUMENT;
+ }
+
+ *lsm_err = NULL;
+ *sd_path_list = lsm_string_list_alloc(0 /* no pre-allocation */);
+ if (*sd_path_list == NULL)
+ return LSM_ERR_NO_MEMORY;
+
+ rc = _sysfs_get_all_sd_names(&sd_name_list);
+ if (rc != LSM_ERR_OK)
+ goto out;
+
+ _lsm_string_list_foreach(sd_name_list, i, sd_name) {
+ if (sd_name == NULL)
+ continue;
+ if (sysfs_support == true) {
+ rc = _sysfs_vpd83_naa_of_sd_name(sd_name, &tmp_vpd83);
+ if (rc == LSM_ERR_NO_SUPPORT)
+ sysfs_support = false;
+ else if (rc != LSM_ERR_OK)
+ break;
+ }
+ /* Try udev way if got NO_SUPPORT from sysfs way. */
+ if (sysfs_support == false) {
+ rc = _udev_vpd83_of_sd_name(sd_name, &tmp_vpd83);
+ if (rc != LSM_ERR_OK)
+ break;
+ }
+ if (tmp_vpd83 == NULL)
+ continue;
+ if (strcmp(vpd83, tmp_vpd83) == 0) {
+ sd_path = (char *) malloc(strlen("/dev/") + strlen(sd_name) +
+ 1 /* trailing \0 */);
+ if (sd_path == NULL)
+ return LSM_ERR_NO_MEMORY;
+
+ sprintf(sd_path, "/dev/%s", sd_name);
+
+ if (lsm_string_list_append(*sd_path_list, sd_path) != 0)
+ return LSM_ERR_NO_MEMORY;
+ free(sd_path);
+ sd_path = NULL;
+ }
+ free(tmp_vpd83);
+ tmp_vpd83 = NULL;
+ }
+
+ out:
+ if (sd_name_list != NULL)
+ lsm_string_list_free(sd_name_list);
+
+ if (rc != LSM_ERR_OK) {
+ *lsm_err = LSM_ERROR_CREATE_PLUGIN_MSG(rc, _lsm_err_msg);
+
+ if (*sd_path_list != NULL)
+ lsm_string_list_free(*sd_path_list);
+
+ *sd_path_list = NULL;
+ }
+ return rc;
+}
diff --git a/configure.ac b/configure.ac
index beae390..908b3cd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -162,6 +162,7 @@ AM_PATH_PYTHON([2.6], [], AC_MSG_ERROR([Python interpreter 2.6 or 2.7 required])
AC_PYTHON_MODULE([pywbem], [Required])
AC_PYTHON_MODULE([M2Crypto], [Required])
AC_PYTHON_MODULE([argparse], [Required])
+PKG_CHECK_MODULES([LIBUDEV], [libudev])

dnl ==========================================================================
dnl Check for libmicrohttpd and json-c as it is needed for REST API daemon
--
1.8.3.1
Gris Ge
2015-11-19 08:22:51 UTC
Permalink
* New function lsm.SCSI.disk_paths_of_vpd83() to search all matching
SCSI disk paths(format: /dev/sd[a-z]+) for given VPD83 ID.

* This function is a wrap of C function lsm_scsi_disk_paths_of_vpd83().

* Updated lsmenv to support C extention (_scsi.so) of python.

* Updated configure.ac to include require of python2-devel.

Signed-off-by: Gris Ge <***@redhat.com>
---
configure.ac | 12 +++++
python_binding/Makefile.am | 9 ++++
python_binding/lsm/__init__.py | 3 ++
python_binding/lsm/_scsi.c | 110 +++++++++++++++++++++++++++++++++++++++++
tools/lsmenv | 4 ++
5 files changed, 138 insertions(+)
create mode 100644 python_binding/lsm/_scsi.c

diff --git a/configure.ac b/configure.ac
index 908b3cd..d99952b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -163,6 +163,18 @@ AC_PYTHON_MODULE([pywbem], [Required])
AC_PYTHON_MODULE([M2Crypto], [Required])
AC_PYTHON_MODULE([argparse], [Required])
PKG_CHECK_MODULES([LIBUDEV], [libudev])
+PKG_CHECK_MODULES([PYTHON2], [python2], [], [not_found_py_pkg=yes])
+
+if test "x$not_found_py_pkg" == "xyes"; then
+ AC_CHECK_PROG([PY_CONFIG_CHECK], [python-config], [yes])
+ if test "x${PY_CONFIG_CHECK}" != "xyes"; then
+ AC_MSG_ERROR([Python2 development libraries required])
+ fi
+ PYTHON2_CFLAGS=`python-config --cflags`
+ PYTHON2_LIBS=`python-config --libs`
+ AC_SUBST(PYTHON2_CFLAGS)
+ AC_SUBST(PYTHON2_LIBS)
+fi

dnl ==========================================================================
dnl Check for libmicrohttpd and json-c as it is needed for REST API daemon
diff --git a/python_binding/Makefile.am b/python_binding/Makefile.am
index 8b0581a..b30d402 100644
--- a/python_binding/Makefile.am
+++ b/python_binding/Makefile.am
@@ -12,6 +12,15 @@ lsm_PYTHON = \
lsm/_iplugin.py \
lsm/_pluginrunner.py

+pyexec_LTLIBRARIES = lsm/_scsi.la
+pyexecdir = $(pythondir)/lsm
+
+lsm__scsi_la_CFLAGS = $(PYTHON2_CFLAGS) -I$(top_srcdir)/c_binding/include
+lsm__scsi_la_SOURCES = lsm/_scsi.c
+lsm__scsi_la_LDFLAGS = $(PYTHON2_LIBS) \
+ -module -avoid-version -export-symbols-regex init_scsi
+lsm__scsi_la_LIBADD = $(top_builddir)/c_binding/libstoragemgmt.la
+
external_PYTHON = \
lsm/external/__init__.py \
lsm/external/xmltodict.py
diff --git a/python_binding/lsm/__init__.py b/python_binding/lsm/__init__.py
index fb1cdbd..503d4ee 100644
--- a/python_binding/lsm/__init__.py
+++ b/python_binding/lsm/__init__.py
@@ -5,6 +5,9 @@
from _common import error, info, LsmError, ErrorNumber, \
JobStatus, uri_parse, md5, Proxy, size_bytes_2_size_human, \
common_urllib2_error_handler, size_human_2_size_bytes
+
+import lsm._scsi as SCSI
+
from _data import (Disk, Volume, Pool, System, FileSystem, FsSnapshot,
NfsExport, BlockRange, AccessGroup, TargetPort,
Capabilities)
diff --git a/python_binding/lsm/_scsi.c b/python_binding/lsm/_scsi.c
new file mode 100644
index 0000000..a0838f2
--- /dev/null
+++ b/python_binding/lsm/_scsi.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Gris Ge <***@redhat.com>
+ */
+
+#include <Python.h>
+#include <stdint.h>
+
+#include <libstoragemgmt/libstoragemgmt.h>
+
+static const char disk_paths_of_vpd83_docstring[] =
+ "Version:\n"
+ " 1.3\n"
+ "Usage:\n"
+ " Find out the /dev/sdX paths for given SCSI VPD page 0x83 NAA type\n"
+ " ID. Considering multipath, certain VPD83 will got multiple disks\n"
+ " associated.\n"
+ "Parameters:\n"
+ " vpd83 (string)\n"
+ " The VPD83 NAA type ID.\n"
+ "Returns:\n"
+ " sd_name (list of string)\n"
+ " Empty list is not found. The string format is '/dev/sd[a-z]+'.\n"
+ "\n"
+ "SpecialExceptions:\n"
+ " N/A\n"
+ "Capability:\n"
+ " N/A\n"
+ " No capability required from plugin as this is a library level\n"
+ " method.";
+
+static PyObject *disk_paths_of_vpd83(PyObject *self, PyObject *args,
+ PyObject *kwargs);
+
+/*
+ * TODO: Support METH_VARARGS | METH_KEYWORDS
+ */
+static PyMethodDef _scsi_methods[] = {
+ {"disk_paths_of_vpd83", (PyCFunction) disk_paths_of_vpd83,
+ METH_VARARGS | METH_KEYWORDS, disk_paths_of_vpd83_docstring},
+ {NULL, NULL, 0, NULL} /* Sentinel */
+};
+
+
+static PyObject *disk_paths_of_vpd83(PyObject *self, PyObject *args,
+ PyObject *kwargs)
+{
+ static const char *kwlist[] = {"vpd83", NULL};
+ const char *vpd83 = NULL;
+ PyObject *rc_list = NULL;
+ lsm_string_list *sd_path_list = NULL;
+ lsm_error *lsm_err = NULL;
+ int rc = LSM_ERR_OK;
+ uint8_t i = 0;
+ const char *sd_path = NULL;
+ PyObject *sd_path_obj = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", (char **) kwlist,
+ &vpd83))
+ return NULL;
+
+ if (vpd83 == NULL)
+ return NULL;
+
+ rc_list = PyList_New(0 /* No pre-allocation */);
+ if (rc_list == NULL)
+ return NULL;
+
+ rc = lsm_scsi_disk_paths_of_vpd83(vpd83, &sd_path_list, &lsm_err);
+ /* In python API defination, we don't raise error in function, only
+ * return empty list.
+ */
+ lsm_error_free(lsm_err);
+
+ if ((rc != LSM_ERR_OK) || (sd_path_list == NULL))
+ return rc_list;
+
+ for (; i < lsm_string_list_size(sd_path_list); ++i) {
+ sd_path = lsm_string_list_elem_get(sd_path_list, i);
+ if (sd_path == NULL)
+ continue;
+ sd_path_obj = PyString_FromString(sd_path);
+ if (sd_path_obj == NULL)
+ return NULL;
+ PyList_Append(rc_list, sd_path_obj);
+ /* ^ PyList_Append will increase the reference count of sd_path_obj */
+ Py_DECREF(sd_path_obj);
+ }
+ lsm_string_list_free(sd_path_list);
+
+ return rc_list;
+}
+
+PyMODINIT_FUNC init_scsi(void)
+{
+ (void) Py_InitModule("_scsi", _scsi_methods);
+}
diff --git a/tools/lsmenv b/tools/lsmenv
index 94055b6..f996d96 100755
--- a/tools/lsmenv
+++ b/tools/lsmenv
@@ -145,6 +145,10 @@ sub lsm_env_setup() {
system("mkdir -pv $LSM_UDS_PATH");
system("chown $LSM_USER $LSM_UDS_PATH");
}
+ unless ( -l "$py_lsm_dir/_scsi.so" ) {
+ print "INFO: Creating softlinke for _scsi.so\n";
+ system("ln -sv .libs/_scsi.so $py_lsm_dir/_scsi.so");
+ }

$ENV{LSM_UDS_PATH} = $LSM_UDS_PATH;
$ENV{PYTHONPATH} .= ":$py_binding_dir";
--
1.8.3.1
Gris Ge
2015-11-19 08:22:52 UTC
Permalink
* The `lsmcli list --type volumes` will include local scsi disks if VPD83
matches. Example:

$ lsmcli lv -s
--------------------------------
ID | VOL_ID_00001
Name | test
SCSI VPD 0x83 | 53333330000007d0
Block Size | 512
Block Count | 2097152
Size | 1073741824
Disabled | No
Pool ID | POOL_ID_00001
System ID | sim-01
Disk Paths | /dev/sda
| /dev/sdf
| /dev/sdh
| /dev/sdj
--------------------------------

Signed-off-by: Gris Ge <***@redhat.com>
---
tools/lsmcli/cmdline.py | 35 +++++++++++++++++++++++------------
tools/lsmcli/data_display.py | 1 +
2 files changed, 24 insertions(+), 12 deletions(-)

diff --git a/tools/lsmcli/cmdline.py b/tools/lsmcli/cmdline.py
index c66eaf2..0b81ced 100644
--- a/tools/lsmcli/cmdline.py
+++ b/tools/lsmcli/cmdline.py
@@ -34,7 +34,7 @@
from lsm import (Client, Pool, VERSION, LsmError, Disk,
Volume, JobStatus, ErrorNumber, BlockRange,
uri_parse, Proxy, size_human_2_size_bytes,
- AccessGroup, FileSystem, NfsExport, TargetPort)
+ AccessGroup, FileSystem, NfsExport, TargetPort, SCSI)

from lsm.lsmcli.data_display import (
DisplayData, PlugData, out,
@@ -904,20 +904,24 @@ def list(self, args):
search_value = args.tgt

if args.type == 'VOLUMES':
+ lsm_vols = []
if search_key == 'volume_id':
search_key = 'id'
if search_key == 'access_group_id':
lsm_ag = _get_item(self.c.access_groups(), args.ag,
"Access Group", raise_error=False)
if lsm_ag:
- return self.display_data(
- self.c.volumes_accessible_by_access_group(lsm_ag))
- else:
- return self.display_data([])
+ lsm_vols = self.c.volumes_accessible_by_access_group(
+ lsm_ag)
elif search_key and search_key not in Volume.SUPPORTED_SEARCH_KEYS:
raise ArgError("Search key '%s' is not supported by "
"volume listing." % search_key)
- self.display_data(self.c.volumes(search_key, search_value))
+ else:
+ lsm_vols = self.c.volumes(search_key, search_value)
+
+ self.display_data(
+ list(self._vol_add_sd_paths(v) for v in lsm_vols))
+
elif args.type == 'POOLS':
if search_key == 'pool_id':
search_key = 'id'
@@ -1023,7 +1027,7 @@ def access_group_volumes(self, args):
agl = self.c.access_groups()
group = _get_item(agl, args.ag, "Access Group")
vols = self.c.volumes_accessible_by_access_group(group)
- self.display_data(vols)
+ self.display_data(list(self._vol_add_sd_paths(v) for v in vols))

def iscsi_chap(self, args):
(init_id, init_type) = parse_convert_init(args.init)
@@ -1163,7 +1167,7 @@ def volume_create(self, args):
args.name,
self._size(args.size),
vol_provision_str_to_type(args.provisioning)))
- self.display_data([vol])
+ self.display_data([self._vol_add_sd_paths(vol)])

## Creates a snapshot
def fs_snap_create(self, args):
@@ -1271,7 +1275,7 @@ def volume_replicate(self, args):
vol = self._wait_for_it(
"replicate volume",
*self.c.volume_replicate(p, rep_type, v, args.name))
- self.display_data([vol])
+ self.display_data([self._vol_add_sd_paths(vol)])

## Replicates a range of a volume
def volume_replicate_range(self, args):
@@ -1324,7 +1328,7 @@ def volume_resize(self, args):
if self.confirm_prompt(False):
vol = self._wait_for_it("resize",
*self.c.volume_resize(v, size))
- self.display_data([vol])
+ self.display_data([self._vol_add_sd_paths(vol)])

## Enable a volume
def volume_enable(self, args):
@@ -1413,8 +1417,9 @@ def volume_raid_create(self, args):
strip_size = Volume.VCR_STRIP_SIZE_DEFAULT

self.display_data([
- self.c.volume_raid_create(
- args.name, raid_type, lsm_disks, strip_size)])
+ self._vol_add_sd_paths(
+ self.c.volume_raid_create(
+ args.name, raid_type, lsm_disks, strip_size))])

def volume_raid_create_cap(self, args):
lsm_sys = _get_item(self.c.systems(), args.sys, "System")
@@ -1536,3 +1541,9 @@ def process(self, cli=None):

self.args.func(self.args)
self.shutdown()
+
+ def _vol_add_sd_paths(self, lsm_vol):
+ lsm_vol.sd_paths = []
+ if len(lsm_vol.vpd83) > 0:
+ lsm_vol.sd_paths = SCSI.disk_paths_of_vpd83(lsm_vol.vpd83)
+ return lsm_vol
diff --git a/tools/lsmcli/data_display.py b/tools/lsmcli/data_display.py
index 2feda46..614d477 100644
--- a/tools/lsmcli/data_display.py
+++ b/tools/lsmcli/data_display.py
@@ -418,6 +418,7 @@ def __init__(self):
VOL_HEADER['admin_state'] = 'Disabled'
VOL_HEADER['pool_id'] = 'Pool ID'
VOL_HEADER['system_id'] = 'System ID'
+ VOL_HEADER['sd_paths'] = 'Disk Paths' # This is appended by cmdline.py

VOL_COLUMN_SKIP_KEYS = ['block_size', 'num_of_blocks']
--
1.8.3.1
Gris Ge
2015-11-19 08:22:53 UTC
Permalink
* Copy .libs/_scsi.so to test folder.

Signed-off-by: Gris Ge <***@redhat.com>
---
test/runtests.sh | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/test/runtests.sh b/test/runtests.sh
index 8b3c499..94949e0 100755
--- a/test/runtests.sh
+++ b/test/runtests.sh
@@ -90,6 +90,7 @@ bin_plugin=$rootdir/plugin/simc/.libs/
lsm_py_folder=$rootdir/python_binding
lsm_plugin_py_folder=$rootdir/plugin
lsmcli_py_folder=$rootdir/tools/lsmcli
+py_scsi_folder=$rootdir/python_binding/lsm/.libs/

if [ -e $rootdir/_build ]
then
@@ -97,6 +98,7 @@ then
LSMD_DAEMON=$rootdir/_build/daemon/lsmd
shared_libs=$rootdir/_build/c_binding/.libs/
bin_plugin=$rootdir/_build/plugin/simc/.libs/
+ py_scsi_folder=$rootdir/_build/python_binding/lsm/.libs/
# In distcheck, all folder is read only(except _build and _inst).
# which prevent us from linking plugin and lsmcli into python/lsm folder.
chmod +w $rootdir/python_binding/lsm
@@ -144,6 +146,9 @@ if [ -e "$PYTHONPATH/lsm/lsmcli" ] || [ -L "$PYTHONPATH/lsm/lsmcli" ];then
fi
good "cp -av $lsmcli_py_folder $PYTHONPATH/lsm/"

+#Copy Python shared library _scsi.so
+good "cp -av $py_scsi_folder/*.so* $PYTHONPATH/lsm/"
+
#Copy plugins to one directory.
good "find $rootdir/ \( ! -regex '.*/\..*' \) -type f -name \*_lsmplugin -exec cp {} $plugins \;"
--
1.8.3.1
Gris Ge
2015-11-19 08:22:54 UTC
Permalink
* Test LSM_ERR_INVALID_ARGUMENT of lsm_scsi_disk_paths_of_vpd83().
* Test dangling pointer of 'sd_path_list' output pointer.

Signed-off-by: Gris Ge <***@redhat.com>
---
test/tester.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 65 insertions(+)

diff --git a/test/tester.c b/test/tester.c
index da2a3a4..7ccd2c8 100644
--- a/test/tester.c
+++ b/test/tester.c
@@ -36,6 +36,7 @@ const char *ISCSI_HOST[2] = { "iqn.1994-05.com.domain:01.89bd01",
static int which_plugin = 0;

#define POLL_SLEEP 50000
+#define VPD83_TO_SEARCH "600508b1001c79ade5178f0626caaa9c"

lsm_connect *c = NULL;

@@ -3083,6 +3084,69 @@ START_TEST(test_volume_raid_create)
}
END_TEST

+
+/*
+ * Just check whether LSM_ERR_INVALID_ARGUMENT handle correctly.
+ */
+START_TEST(test_scsi_disk_paths_of_vpd83)
+{
+ int rc = LSM_ERR_OK;
+ lsm_string_list *sd_path_list;
+ /* Not initialized in order to test dangling pointer sd_path_list */
+ lsm_error *lsm_err;
+ /* Not initialized in order to test dangling pointer lsm_err */
+
+ if (which_plugin == 1){
+ /* silently skip on simc, no need for duplicate test. */
+ return;
+ }
+
+ rc = lsm_scsi_disk_paths_of_vpd83(NULL, &sd_path_list, &lsm_err);
+ fail_unless(rc == LSM_ERR_INVALID_ARGUMENT,
+ "lsm_scsi_disk_paths_of_vpd83(): Expecting "
+ "LSM_ERR_INVALID_ARGUMENT when vpd83 argument pointer is NULL");
+
+ fail_unless(sd_path_list == NULL,
+ "lsm_scsi_disk_paths_of_vpd83(): Expecting "
+ "sd_path_list been set as NULL.");
+
+ fail_unless(lsm_err == NULL,
+ "lsm_scsi_disk_paths_of_vpd83(): Expecting "
+ "lsm_err been set as NULL.");
+
+ rc = lsm_scsi_disk_paths_of_vpd83(VPD83_TO_SEARCH, NULL, &lsm_err);
+ fail_unless(rc == LSM_ERR_INVALID_ARGUMENT,
+ "lsm_scsi_disk_paths_of_vpd83(): Expecting "
+ "LSM_ERR_INVALID_ARGUMENT when sd_path_list argument pointer "
+ "is NULL");
+
+ rc = lsm_scsi_disk_paths_of_vpd83(VPD83_TO_SEARCH, &sd_path_list, NULL);
+ fail_unless(rc == LSM_ERR_INVALID_ARGUMENT,
+ "lsm_scsi_disk_paths_of_vpd83(): Expecting "
+ "LSM_ERR_INVALID_ARGUMENT when lsm_err argument pointer "
+ "is NULL");
+
+ rc = lsm_scsi_disk_paths_of_vpd83(VPD83_TO_SEARCH, &sd_path_list, &lsm_err);
+ fail_unless(rc == LSM_ERR_OK,
+ "lsm_scsi_disk_paths_of_vpd83(): Expecting LSM_ERR_OK"
+ "when no argument is NULL");
+
+ fail_unless(lsm_err == NULL,
+ "lsm_scsi_disk_paths_of_vpd83(): Expecting lsm_err as NULL"
+ "when no argument is NULL");
+
+ if (sd_path_list != NULL)
+ lsm_string_list_free(sd_path_list);
+
+ if (lsm_err != NULL)
+ lsm_error_free(lsm_err);
+ /* ^ No need to free lsm_err as programme already quit due to above check,
+ * keeping this line is just for code demonstration.
+ */
+}
+END_TEST
+
+
Suite * lsm_suite(void)
{
Suite *s = suite_create("libStorageMgmt");
@@ -3124,6 +3188,7 @@ Suite * lsm_suite(void)
tcase_add_test(basic, test_pool_member_info);
tcase_add_test(basic, test_volume_raid_create_cap_get);
tcase_add_test(basic, test_volume_raid_create);
+ tcase_add_test(basic, test_scsi_disk_paths_of_vpd83);

suite_add_tcase(s, basic);
return s;
--
1.8.3.1
Gris Ge
2015-11-19 08:22:55 UTC
Permalink
* Add the new python_binding/lsm/_scsi.so file.
* Add build require for libudev and python-devel.
* Remove noarch type of libstoragemgmt-python package.

Signed-off-by: Gris Ge <***@redhat.com>
---
packaging/libstoragemgmt.spec.in | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/packaging/libstoragemgmt.spec.in b/packaging/libstoragemgmt.spec.in
index 00da8c8..f1dba06 100644
--- a/packaging/libstoragemgmt.spec.in
+++ b/packaging/libstoragemgmt.spec.in
@@ -70,6 +70,13 @@ BuildRequires: libyajl-devel
BuildRequires: yajl-devel
%endif

+%if 0%{?rhel} == 6
+BuildRequires: libudev-devel
+%else
+BuildRequires: systemd-devel
+%endif
+BuildRequires: python-devel
+
%if 0%{?do_fdupes}
BuildRequires: fdupes
%endif
@@ -122,7 +129,6 @@ developing applications that use %{name}.
Summary: Python client libraries and plug-in support for %{libstoragemgmt}
Group: System Environment/Libraries
Requires: %{libstoragemgmt} = %{version}-%{release}
-BuildArch: noarch
Requires: python-argparse
%if 0%{?rhel} == 6
# No way to detect 6.2 yet. Just forcing all RHEL 6 to install
@@ -540,6 +546,7 @@ fi
%{python_sitelib}/lsm/external/*
%{python_sitelib}/lsm/_client.*
%{python_sitelib}/lsm/_common.*
+%{python_sitelib}/lsm/_scsi.*
%{python_sitelib}/lsm/_data.*
%{python_sitelib}/lsm/_iplugin.*
%{python_sitelib}/lsm/_pluginrunner.*
--
1.8.3.1
Gris Ge
2015-11-19 08:22:56 UTC
Permalink
* Just allow python absolute import like:
from lsm._scsi import SCSI

Signed-off-by: Gris Ge <***@redhat.com>
---
tools/utility/check_const.pl | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/tools/utility/check_const.pl b/tools/utility/check_const.pl
index 64abf34..2b2eead 100644
--- a/tools/utility/check_const.pl
+++ b/tools/utility/check_const.pl
@@ -267,7 +267,14 @@ sub _parse_py_init_file($) {

foreach my $line (@lines) {
if ( $line =~ /from ([^ ]+) import (.+)$/ ) {
- push @rc1, sprintf "%s/%s.py", $folder_path, $1;
+ my $module_file_name = $1;
+ if ($module_file_name =~ /^lsm\.(.+)$/) {
+ $module_file_name = $1;
+ $module_file_name =~ s|\.|/|g;
+ push @rc1, sprintf "%s/%s.py", $folder_path, $module_file_name;
+ } else {
+ push @rc1, sprintf "%s/%s.py", $folder_path, $module_file_name;
+ }
my $class_line = $2;
while ( $class_line =~ /([A-Z][a-zA-Z]+)[, \\]*/g ) {
push @rc2, $1;
--
1.8.3.1
Gris Ge
2015-11-19 08:22:57 UTC
Permalink
* New "Disk Name" column added to volume listing, which cause list[-2]
does not pointing to pool id, changed it to index number 5.

Signed-off-by: Gris Ge <***@redhat.com>
---
test/cmdtest.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/cmdtest.py b/test/cmdtest.py
index 7fa6599..bbf39a4 100755
--- a/test/cmdtest.py
+++ b/test/cmdtest.py
@@ -750,7 +750,7 @@ def volume_raid_create_test(cap, system_id):

volume = parse(out)
vol_id = volume[0][0]
- pool_id = volume[0][-2]
+ pool_id = volume[0][5]

if cap['VOLUME_RAID_INFO']:
out = call(
--
1.8.3.1
Gris Ge
2015-11-19 08:22:58 UTC
Permalink
* Use random generated volume name for volume_raid_create_test() test.

Signed-off-by: Gris Ge <***@redhat.com>
---
test/cmdtest.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/test/cmdtest.py b/test/cmdtest.py
index bbf39a4..22ee372 100755
--- a/test/cmdtest.py
+++ b/test/cmdtest.py
@@ -745,7 +745,8 @@ def volume_raid_create_test(cap, system_id):

out = call([
cmd, '-t' + sep, 'volume-raid-create', '--disk', free_disk_ids[0],
- '--disk', free_disk_ids[1], '--name', 'test_volume_raid_create',
+ '--disk', free_disk_ids[1], '--name',
+ 'test_volume_raid_create_%s' % rs(4),
'--raid-type', 'raid1'])[1]

volume = parse(out)
--
1.8.3.1
Gris Ge
2015-11-19 08:22:59 UTC
Permalink
* New these packages for libudev and pyudev:
* python-dev
* libudev-dev

Signed-off-by: Gris Ge <***@redhat.com>
---
.travis.yml | 2 ++
1 file changed, 2 insertions(+)

diff --git a/.travis.yml b/.travis.yml
index f267aed..25800e0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -19,6 +19,8 @@ addons:
- python-m2crypto
- libssl-dev
- libconfig-dev
+ - libudev-dev
+ - python-dev

compiler: gcc
--
1.8.3.1
Gris Ge
2015-11-19 08:23:00 UTC
Permalink
* In distcheck, all code folder has not write permission which
cause clean up method cannot remove python modules in /tmp folder.
Error message:

rm: cannot remove `/tmp/9472/python/lsm/external/__init__.py': Permission
denied

* Fixed by add writing permission to /tmp/<random> folder recursively before
removal.

Signed-off-by: Gris Ge <***@redhat.com>
---
test/runtests.sh | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/test/runtests.sh b/test/runtests.sh
index 94949e0..bf3f95f 100755
--- a/test/runtests.sh
+++ b/test/runtests.sh
@@ -45,15 +45,9 @@ cleanup() {
cat $LSMD_TMP_LOG_FILE
if [ -e $LSM_UDS_PATH ]
then
+ chmod +w -R $base
rm -rf $base
fi
-
- if [ -e $rootdir/_build ]
- then
- rm $lsm_py_folder/lsm/plugin
- rm $lsm_py_folder/lsm/lsmcli
- chmod -w $lsm_py_folder/lsm
- fi
}

good() {
--
1.8.3.1
Loading...