Tony Asleson
2014-08-27 23:30:20 UTC
Some arrays don't support all features for all pools. Add propery
so that we can convey this information.
Signed-off-by: Tony Asleson <***@redhat.com>
---
.../libstoragemgmt/libstoragemgmt_plug_interface.h | 2 ++
.../include/libstoragemgmt/libstoragemgmt_pool.h | 7 ++++
.../include/libstoragemgmt/libstoragemgmt_types.h | 3 ++
c_binding/lsm_convert.cpp | 2 ++
c_binding/lsm_datatypes.cpp | 6 ++++
c_binding/lsm_datatypes.hpp | 1 +
plugin/nstor/nstor.py | 1 +
plugin/ontap/ontap.py | 2 +-
plugin/sim/simarray.py | 10 +++++-
plugin/simc/simc_lsmplugin.c | 6 ++--
plugin/smispy/smis.py | 40 ++++++++++++++++------
plugin/targetd/targetd.py | 2 +-
python_binding/lsm/_data.py | 10 +++++-
test/plugin_test.py | 12 ++++---
tools/lsmcli/data_display.py | 14 +++++++-
15 files changed, 94 insertions(+), 24 deletions(-)
diff --git a/c_binding/include/libstoragemgmt/libstoragemgmt_plug_interface.h b/c_binding/include/libstoragemgmt/libstoragemgmt_plug_interface.h
index 518f5c0..635fdef 100644
--- a/c_binding/include/libstoragemgmt/libstoragemgmt_plug_interface.h
+++ b/c_binding/include/libstoragemgmt/libstoragemgmt_plug_interface.h
@@ -910,6 +910,7 @@ void LSM_DLL_EXPORT lsm_pool_free_space_set(lsm_pool *p, uint64_t free_space);
* @param name Human readable name
* @param element_type A bit field which states what the pool can be used to
* create
+ * @param unsupported_actions Things you cannot do with this pool
* @param total_space Total space
* @param free_space Space available
* @param status Pool status, bit field (See LSM_POOL_STATUS_XXXX constants)
@@ -920,6 +921,7 @@ void LSM_DLL_EXPORT lsm_pool_free_space_set(lsm_pool *p, uint64_t free_space);
*/
lsm_pool LSM_DLL_EXPORT *lsm_pool_record_alloc(const char *id, const char *name,
uint64_t element_type,
+ uint64_t unsupported_actions,
uint64_t total_space,
uint64_t free_space,
uint64_t status, const char* status_info,
diff --git a/c_binding/include/libstoragemgmt/libstoragemgmt_pool.h b/c_binding/include/libstoragemgmt/libstoragemgmt_pool.h
index 390cff0..6ddfed0 100644
--- a/c_binding/include/libstoragemgmt/libstoragemgmt_pool.h
+++ b/c_binding/include/libstoragemgmt/libstoragemgmt_pool.h
@@ -107,6 +107,13 @@ char LSM_DLL_EXPORT *lsm_pool_system_id_get( lsm_pool *p );
*/
uint64_t LSM_DLL_EXPORT lsm_pool_element_type_get( lsm_pool *p );
+/**
+ * Retrieve what the pool cannot be used for.
+ * @param p Pool pointer
+ * @return bitmap of actions not supported.
+ */
+uint64_t LSM_DLL_EXPORT lsm_pool_unsupported_actions_get( lsm_pool *p);
+
#ifdef __cplusplus
}
#endif
diff --git a/c_binding/include/libstoragemgmt/libstoragemgmt_types.h b/c_binding/include/libstoragemgmt/libstoragemgmt_types.h
index ec81bb9..653c1fa 100644
--- a/c_binding/include/libstoragemgmt/libstoragemgmt_types.h
+++ b/c_binding/include/libstoragemgmt/libstoragemgmt_types.h
@@ -223,6 +223,9 @@ typedef enum {
#define LSM_POOL_ELEMENT_TYPE_DELTA 0x0000000000000010
#define LSM_POOL_ELEMENT_TYPE_SYS_RESERVED 0x0000000000000400
+#define LSM_POOL_UNSUPPORTED_VOLUME_EXPAND 0x0000000000000001
+#define LSM_POOL_UNSUPPORTED_VOLUME_SHRINK 0x0000000000000002
+
typedef enum {
LSM_TARGET_PORT_TYPE_UNKNOWN = 0,
LSM_TARGET_PORT_TYPE_OTHER = 1,
diff --git a/c_binding/lsm_convert.cpp b/c_binding/lsm_convert.cpp
index f3693eb..7baf2e6 100644
--- a/c_binding/lsm_convert.cpp
+++ b/c_binding/lsm_convert.cpp
@@ -191,6 +191,7 @@ lsm_pool *value_to_pool(Value &pool)
rc = lsm_pool_record_alloc(i["id"].asString().c_str(),
i["name"].asString().c_str(),
i["element_type"].asUint64_t(),
+ i["unsupported_actions"].asUint64_t(),
i["total_space"].asUint64_t(),
i["free_space"].asUint64_t(),
i["status"].asUint64_t(),
@@ -209,6 +210,7 @@ Value pool_to_value(lsm_pool *pool)
p["id"] = Value(pool->id);
p["name"] = Value(pool->name);
p["element_type"] = Value(pool->element_type);
+ p["unsupported_actions"] = Value(pool->unsupported_actions);
p["total_space"] = Value(pool->total_space);
p["free_space"] = Value(pool->free_space);
p["status"] = Value(pool->status);
diff --git a/c_binding/lsm_datatypes.cpp b/c_binding/lsm_datatypes.cpp
index a0248b2..8363326 100644
--- a/c_binding/lsm_datatypes.cpp
+++ b/c_binding/lsm_datatypes.cpp
@@ -484,6 +484,7 @@ CREATE_ALLOC_ARRAY_FUNC(lsm_pool_record_array_alloc, lsm_pool *)
lsm_pool *lsm_pool_record_alloc(const char *id, const char *name,
uint64_t element_type,
+ uint64_t unsupported_actions,
uint64_t totalSpace, uint64_t freeSpace, uint64_t status,
const char* status_info,
const char *system_id, const char * plugin_data)
@@ -494,6 +495,7 @@ lsm_pool *lsm_pool_record_alloc(const char *id, const char *name,
rc->id = strdup(id);
rc->name = strdup(name);
rc->element_type = element_type;
+ rc->unsupported_actions = unsupported_actions;
rc->total_space = totalSpace;
rc->free_space = freeSpace;
rc->status = status;
@@ -525,6 +527,7 @@ lsm_pool * lsm_pool_record_copy( lsm_pool *toBeCopied)
if( LSM_IS_POOL(toBeCopied) ) {
return lsm_pool_record_alloc(toBeCopied->id, toBeCopied->name,
toBeCopied->element_type,
+ toBeCopied->unsupported_actions,
toBeCopied->total_space,
toBeCopied->free_space,
toBeCopied->status,
@@ -633,6 +636,9 @@ MEMBER_FUNC_GET(const char *, lsm_pool_plugin_data_get, lsm_pool *p,
MEMBER_FUNC_GET( uint64_t, lsm_pool_element_type_get, lsm_pool *p, p, LSM_IS_POOL,
element_type, 0)
+MEMBER_FUNC_GET( uint64_t, lsm_pool_unsupported_actions_get, lsm_pool *p, p,
+ LSM_IS_POOL, element_type, 0)
+
CREATE_ALLOC_ARRAY_FUNC(lsm_volume_record_array_alloc, lsm_volume *)
lsm_volume * lsm_volume_record_alloc(const char *id, const char *name,
diff --git a/c_binding/lsm_datatypes.hpp b/c_binding/lsm_datatypes.hpp
index 27976db..dbeaca1 100644
--- a/c_binding/lsm_datatypes.hpp
+++ b/c_binding/lsm_datatypes.hpp
@@ -81,6 +81,7 @@ struct LSM_DLL_LOCAL _lsm_pool {
char *id; /**< System wide unique identifier */
char *name; /**< Human recognizeable name */
uint64_t element_type; /**< What the pool can be used for */
+ uint64_t unsupported_actions; /**< What pool cannot be used for */
uint64_t total_space; /**< Total size */
uint64_t free_space; /**< Free space available */
uint64_t status; /**< Status of pool */
diff --git a/plugin/nstor/nstor.py b/plugin/nstor/nstor.py
index c5e3ef1..98b73be 100644
--- a/plugin/nstor/nstor.py
+++ b/plugin/nstor/nstor.py
@@ -134,6 +134,7 @@ class NexentaStor(INfs, IStorageAreaNetwork):
pools.append(Pool(pool_info['name'], pool_info['name'],
Pool.ELEMENT_TYPE_VOLUME | Pool.ELEMENT_TYPE_FS,
+ 0,
NexentaStor._to_bytes(pool_info['size']),
NexentaStor._to_bytes(pool_info['free']),
Pool.STATUS_UNKNOWN, '', self.system.id))
diff --git a/plugin/ontap/ontap.py b/plugin/ontap/ontap.py
index 5dcbcc7..02e7a33 100644
--- a/plugin/ontap/ontap.py
+++ b/plugin/ontap/ontap.py
@@ -451,7 +451,7 @@ class Ontap(IStorageAreaNetwork, INfs):
if pool_name == '/vol/vol0':
element_type |= Pool.ELEMENT_TYPE_SYS_RESERVED
- return Pool(pool_id, pool_name, element_type, total_space, free_space,
+ return Pool(pool_id, pool_name, element_type, 0, total_space, free_space,
status, status_info, system_id)
@handle_ontap_errors
diff --git a/plugin/sim/simarray.py b/plugin/sim/simarray.py
index f391681..1d5f517 100644
--- a/plugin/sim/simarray.py
+++ b/plugin/sim/simarray.py
@@ -221,9 +221,10 @@ class SimArray(object):
status = sim_pool['status']
status_info = sim_pool['status_info']
sys_id = sim_pool['sys_id']
+ unsupported_actions = sim_pool['unsupported_actions']
return Pool(pool_id, name,
Pool.ELEMENT_TYPE_VOLUME | Pool.ELEMENT_TYPE_FS,
- total_space, free_space, status,
+ unsupported_actions, total_space, free_space, status,
status_info, sys_id)
def pools(self, flags=0):
@@ -552,6 +553,8 @@ class SimData(object):
| Pool.ELEMENT_TYPE_POOL \
| Pool.ELEMENT_TYPE_VOLUME
+ SIM_DATA_POOL_UNSUPPORTED_ACTIONS = 0
+
SIM_DATA_SYS_POOL_ELEMENT_TYPE = SIM_DATA_POOL_ELEMENT_TYPE \
| Pool.ELEMENT_TYPE_SYS_RESERVED
@@ -617,6 +620,8 @@ class SimData(object):
'status_info': SimData.SIM_DATA_POOL_STATUS_INFO,
'sys_id': SimData.SIM_DATA_SYS_ID,
'element_type': SimData.SIM_DATA_SYS_POOL_ELEMENT_TYPE,
+ 'unsupported_actions': Pool.UNSUPPORTED_VOLUME_EXPAND | \
+ Pool.UNSUPPORTED_VOLUME_SHRINK
},
'POO2': {
'pool_id': 'POO2',
@@ -629,6 +634,7 @@ class SimData(object):
'status_info': SimData.SIM_DATA_POOL_STATUS_INFO,
'sys_id': SimData.SIM_DATA_SYS_ID,
'element_type': SimData.SIM_DATA_POOL_ELEMENT_TYPE,
+ 'unsupported_actions': SimData.SIM_DATA_POOL_UNSUPPORTED_ACTIONS
},
# lsm_test_aggr pool is required by test/runtest.sh
'lsm_test_aggr': {
@@ -641,6 +647,7 @@ class SimData(object):
'status_info': SimData.SIM_DATA_POOL_STATUS_INFO,
'sys_id': SimData.SIM_DATA_SYS_ID,
'element_type': SimData.SIM_DATA_POOL_ELEMENT_TYPE,
+ 'unsupported_actions': SimData.SIM_DATA_POOL_UNSUPPORTED_ACTIONS
},
}
self.vol_dict = {
@@ -701,6 +708,7 @@ class SimData(object):
'status_info': SimData.SIM_DATA_POOL_STATUS_INFO,
'sys_id': SimData.SIM_DATA_SYS_ID,
'element_type': SimData.SIM_DATA_POOL_ELEMENT_TYPE,
+ 'unsupported_actions': SimData.SIM_DATA_POOL_UNSUPPORTED_ACTIONS
}
self.tgt_dict = {
diff --git a/plugin/simc/simc_lsmplugin.c b/plugin/simc/simc_lsmplugin.c
index 7c55337..e2e28da 100644
--- a/plugin/simc/simc_lsmplugin.c
+++ b/plugin/simc/simc_lsmplugin.c
@@ -2119,10 +2119,10 @@ int load( lsm_plugin_ptr c, const char *uri, const char *password,
p = lsm_pool_record_alloc("POOL_3", "lsm_test_aggr",
LSM_POOL_ELEMENT_TYPE_FS|
- LSM_POOL_ELEMENT_TYPE_VOLUME,
+ LSM_POOL_ELEMENT_TYPE_VOLUME, 0,
UINT64_MAX, UINT64_MAX,
LSM_POOL_STATUS_OK, "",
- sys_id, NULL);
+ sys_id, 0);
if( p ) {
pd->pools = g_hash_table_new_full(g_str_hash, g_str_equal, free,
free_pool_record);
@@ -2134,7 +2134,7 @@ int load( lsm_plugin_ptr c, const char *uri, const char *password,
snprintf(name, sizeof(name), "POOL_%d", i);
p = lsm_pool_record_alloc(name, name, LSM_POOL_ELEMENT_TYPE_FS|
- LSM_POOL_ELEMENT_TYPE_VOLUME, UINT64_MAX,
+ LSM_POOL_ELEMENT_TYPE_VOLUME, 0, UINT64_MAX,
UINT64_MAX, LSM_POOL_STATUS_OK, "",
sys_id, NULL);
diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index 5a7f2b2..048de69 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -255,12 +255,16 @@ class Smis(IStorageAreaNetwork):
JOB_RETRIEVE_POOL = 2
# DMTF CIM 2.37.0 experimental CIM_StoragePool['Usage']
- DMTF_POOL_USAGE_SPARE = 8
+ DMTF_POOL_USAGE_UNRESTRICTED = 2
+ DMTF_POOL_USAGE_RESERVED_FOR_SYSTEM = 3
DMTF_POOL_USAGE_DELTA = 4
+ DMTF_POOL_USAGE_SPARE = 8
# DMTF CIM 2.29.1 CIM_StorageConfigurationCapabilities
# ['SupportedStorageElementFeatures']
DMTF_SUPPORT_VOL_CREATE = 3
+ DMTF_SUPPORT_ELEMENT_EXPAND = 12
+ DMTF_SUPPORT_ELEMENT_REDUCE = 13
# DMTF CIM 2.37.0 experimental CIM_StorageConfigurationCapabilities
# ['SupportedStorageElementTypes']
@@ -1650,9 +1654,10 @@ class Smis(IStorageAreaNetwork):
(status, status_info) = DMTF.cim_pool_status_of(
cim_pool['OperationalStatus'])
- element_type = self._pool_element_type(cim_pool)
+ element_type, unsupported = self._pool_element_type(cim_pool)
- return Pool(pool_id, name, element_type, total_space, free_space,
+ return Pool(pool_id, name, element_type, unsupported,
+ total_space, free_space,
status, status_info, system_id)
@staticmethod
@@ -3171,6 +3176,7 @@ class Smis(IStorageAreaNetwork):
def _pool_element_type(self, cim_pool):
element_type = 0
+ unsupported = 0
# check whether current pool support create volume or not.
cim_sccs = self._c.Associators(
@@ -3185,10 +3191,16 @@ class Smis(IStorageAreaNetwork):
# Manipulation, Figure 9 - Capabilities Specific to a StoragePool
if len(cim_sccs) == 1:
cim_scc = cim_sccs[0]
- if 'SupportedStorageElementFeatures' in cim_scc and \
- Smis.DMTF_SUPPORT_VOL_CREATE in \
- cim_scc['SupportedStorageElementFeatures']:
- element_type = Pool.ELEMENT_TYPE_VOLUME
+ if 'SupportedStorageElementFeatures' in cim_scc:
+ supported_features = cim_scc['SupportedStorageElementFeatures']
+
+ if Smis.DMTF_SUPPORT_VOL_CREATE in supported_features:
+ element_type |= Pool.ELEMENT_TYPE_VOLUME
+ if Smis.DMTF_SUPPORT_ELEMENT_EXPAND not in supported_features:
+ unsupported |= Pool.UNSUPPORTED_VOLUME_EXPAND
+ if Smis.DMTF_SUPPORT_ELEMENT_REDUCE not in supported_features:
+ unsupported |= Pool.UNSUPPORTED_VOLUME_SHRINK
+
else:
# IBM DS 8000 does not support StorageConfigurationCapabilities
# per pool yet. They has been informed. Before fix, use a quick
@@ -3205,12 +3217,18 @@ class Smis(IStorageAreaNetwork):
element_type = Pool.ELEMENT_TYPE_VOLUME
if 'Usage' in cim_pool:
- if cim_pool['Usage'] == Smis.DMTF_POOL_USAGE_DELTA:
+ usage = cim_pool['Usage']
+
+ if usage == Smis.DMTF_POOL_USAGE_UNRESTRICTED:
+ element_type |= Pool.ELEMENT_TYPE_VOLUME
+ if usage == Smis.DMTF_POOL_USAGE_RESERVED_FOR_SYSTEM or \
+ usage > Smis.DMTF_POOL_USAGE_DELTA:
+ element_type |= Pool.ELEMENT_TYPE_SYS_RESERVED
+ if usage == Smis.DMTF_POOL_USAGE_DELTA:
+ # We blitz all the other elements types for this designation
element_type = Pool.ELEMENT_TYPE_DELTA
- if cim_pool['Usage'] == 2:
- element_type = Pool.ELEMENT_TYPE_VOLUME
- return element_type
+ return element_type, unsupported
def _profile_is_supported(self, profile_name, spec_ver, strict=False,
raise_error=False):
diff --git a/plugin/targetd/targetd.py b/plugin/targetd/targetd.py
index 989dbf5..26537a5 100644
--- a/plugin/targetd/targetd.py
+++ b/plugin/targetd/targetd.py
@@ -180,7 +180,7 @@ class TargetdStorage(IStorageAreaNetwork, INfs):
et = Pool.ELEMENT_TYPE_VOLUME
pools.append(Pool(pool['name'],
- pool['name'], et, pool['size'],
+ pool['name'], et, 0, pool['size'],
pool['free_size'], Pool.STATUS_UNKNOWN, '',
'targetd'))
return search_property(pools, search_key, search_value)
diff --git a/python_binding/lsm/_data.py b/python_binding/lsm/_data.py
index b7f3290..43614b9 100644
--- a/python_binding/lsm/_data.py
+++ b/python_binding/lsm/_data.py
@@ -308,6 +308,7 @@ class System(IData):
@default_property('system_id', doc="System identifier")
@default_property("plugin_data", doc="Plug-in private data")
@default_property("element_type", doc="What pool can be used for")
+@default_property("unsupported_actions", doc="What cannot be done with this pool")
class Pool(IData):
"""
Pool specific information
@@ -328,6 +329,10 @@ class Pool(IData):
ELEMENT_TYPE_DELTA = 1 << 4
ELEMENT_TYPE_SYS_RESERVED = 1 << 10 # Reserved for system use
+ # Unsupported actions, what pool cannot be used for
+ UNSUPPORTED_VOLUME_EXPAND = 1 << 0
+ UNSUPPORTED_VOLUME_SHRINK = 1 << 1
+
# Pool status could be any combination of these status.
STATUS_UNKNOWN = 1 << 0
STATUS_OK = 1 << 1
@@ -343,11 +348,14 @@ class Pool(IData):
STATUS_GROWING = 1 << 15
STATUS_DESTROYING = 1 << 17
- def __init__(self, _id, _name, _element_type, _total_space, _free_space,
+ def __init__(self, _id, _name, _element_type, _unsupported_actions,
+ _total_space, _free_space,
_status, _status_info, _system_id, _plugin_data=None):
self._id = _id # Identifier
self._name = _name # Human recognisable name
self._element_type = _element_type # What pool can be used to create
+ self._unsupported_actions = _unsupported_actions # What pool cannot be
+ # used for
self._total_space = _total_space # Total size
self._free_space = _free_space # Free space available
self._status = _status # Status of pool.
diff --git a/test/plugin_test.py b/test/plugin_test.py
index 042835a..75e3650 100755
--- a/test/plugin_test.py
+++ b/test/plugin_test.py
@@ -271,9 +271,11 @@ class TestPlugin(unittest.TestCase):
for p in self.pool_by_sys_id[system_id]:
# If the pool matches our criteria and min size we will consider
# it, but we will select the one with the most free space for
- # testing.
+ # testing and one that support volume expansion
if p.element_type & element_type and \
- p.free_space > mb_in_bytes(MIN_POOL_SIZE):
+ p.free_space > mb_in_bytes(MIN_POOL_SIZE) and \
+ (not p.unsupported_actions &
+ lsm.Pool.UNSUPPORTED_VOLUME_EXPAND):
if p.free_space > largest_free:
largest_free = p.free_space
rc = p
@@ -340,10 +342,10 @@ class TestPlugin(unittest.TestCase):
disks = self.c.disks()
self.assertTrue(len(disks) > 0, "We need at least 1 disk to test")
- def _volume_create(self, system_id):
+ def _volume_create(self, system_id,
+ element_type=lsm.Pool.ELEMENT_TYPE_VOLUME):
if system_id in self.pool_by_sys_id:
- p = self._get_pool_by_usage(system_id,
- lsm.Pool.ELEMENT_TYPE_VOLUME)
+ p = self._get_pool_by_usage(system_id, element_type)
self.assertTrue(p is not None, "Unable to find a suitable pool")
diff --git a/tools/lsmcli/data_display.py b/tools/lsmcli/data_display.py
index 8fab818..080f6fa 100644
--- a/tools/lsmcli/data_display.py
+++ b/tools/lsmcli/data_display.py
@@ -52,7 +52,8 @@ def _bit_map_to_str(bit_map, conv_dict):
for cur_enum in conv_dict.keys():
if cur_enum & bit_map:
rc.append(conv_dict[cur_enum])
- if len(rc) == 0:
+ # If there are no bits set we really don't need a string
+ if bit_map != 0 and len(rc) == 0:
return 'Unknown(%s)' % hex(bit_map)
return BIT_MAP_STRING_SPLITTER.join(rc)
@@ -118,11 +119,20 @@ _POOL_ELEMENT_TYPE_CONV = {
Pool.ELEMENT_TYPE_DELTA: "DELTA",
}
+_POOL_UNSUPPORTED_ACTION_CONV = {
+ Pool.UNSUPPORTED_VOLUME_EXPAND: "Volume expand",
+ Pool.UNSUPPORTED_VOLUME_SHRINK: "Volume shrink"
+}
+
def pool_element_type_to_str(element_type):
return _bit_map_to_str(element_type, _POOL_ELEMENT_TYPE_CONV)
+def pool_unsupported_actions_to_str(unsupported_action):
+ return _bit_map_to_str(unsupported_action, _POOL_UNSUPPORTED_ACTION_CONV)
+
+
_VOL_PROVISION_CONV = {
Volume.PROVISION_DEFAULT: 'DEFAULT',
Volume.PROVISION_FULL: 'FULL',
@@ -299,6 +309,7 @@ class DisplayData(object):
POOL_MAN_HEADER['id'] = 'ID'
POOL_MAN_HEADER['name'] = 'Name'
POOL_MAN_HEADER['element_type'] = 'Element type'
+ POOL_MAN_HEADER['unsupported_actions'] = 'Does not support'
POOL_MAN_HEADER['total_space'] = 'Total Space'
POOL_MAN_HEADER['free_space'] = 'Free Space'
POOL_MAN_HEADER['status'] = 'Status'
@@ -310,6 +321,7 @@ class DisplayData(object):
POOL_VALUE_CONV_ENUM = {
'status': pool_status_to_str,
'element_type': pool_element_type_to_str,
+ 'unsupported_actions': pool_unsupported_actions_to_str
}
POOL_VALUE_CONV_HUMAN = ['total_space', 'free_space']
so that we can convey this information.
Signed-off-by: Tony Asleson <***@redhat.com>
---
.../libstoragemgmt/libstoragemgmt_plug_interface.h | 2 ++
.../include/libstoragemgmt/libstoragemgmt_pool.h | 7 ++++
.../include/libstoragemgmt/libstoragemgmt_types.h | 3 ++
c_binding/lsm_convert.cpp | 2 ++
c_binding/lsm_datatypes.cpp | 6 ++++
c_binding/lsm_datatypes.hpp | 1 +
plugin/nstor/nstor.py | 1 +
plugin/ontap/ontap.py | 2 +-
plugin/sim/simarray.py | 10 +++++-
plugin/simc/simc_lsmplugin.c | 6 ++--
plugin/smispy/smis.py | 40 ++++++++++++++++------
plugin/targetd/targetd.py | 2 +-
python_binding/lsm/_data.py | 10 +++++-
test/plugin_test.py | 12 ++++---
tools/lsmcli/data_display.py | 14 +++++++-
15 files changed, 94 insertions(+), 24 deletions(-)
diff --git a/c_binding/include/libstoragemgmt/libstoragemgmt_plug_interface.h b/c_binding/include/libstoragemgmt/libstoragemgmt_plug_interface.h
index 518f5c0..635fdef 100644
--- a/c_binding/include/libstoragemgmt/libstoragemgmt_plug_interface.h
+++ b/c_binding/include/libstoragemgmt/libstoragemgmt_plug_interface.h
@@ -910,6 +910,7 @@ void LSM_DLL_EXPORT lsm_pool_free_space_set(lsm_pool *p, uint64_t free_space);
* @param name Human readable name
* @param element_type A bit field which states what the pool can be used to
* create
+ * @param unsupported_actions Things you cannot do with this pool
* @param total_space Total space
* @param free_space Space available
* @param status Pool status, bit field (See LSM_POOL_STATUS_XXXX constants)
@@ -920,6 +921,7 @@ void LSM_DLL_EXPORT lsm_pool_free_space_set(lsm_pool *p, uint64_t free_space);
*/
lsm_pool LSM_DLL_EXPORT *lsm_pool_record_alloc(const char *id, const char *name,
uint64_t element_type,
+ uint64_t unsupported_actions,
uint64_t total_space,
uint64_t free_space,
uint64_t status, const char* status_info,
diff --git a/c_binding/include/libstoragemgmt/libstoragemgmt_pool.h b/c_binding/include/libstoragemgmt/libstoragemgmt_pool.h
index 390cff0..6ddfed0 100644
--- a/c_binding/include/libstoragemgmt/libstoragemgmt_pool.h
+++ b/c_binding/include/libstoragemgmt/libstoragemgmt_pool.h
@@ -107,6 +107,13 @@ char LSM_DLL_EXPORT *lsm_pool_system_id_get( lsm_pool *p );
*/
uint64_t LSM_DLL_EXPORT lsm_pool_element_type_get( lsm_pool *p );
+/**
+ * Retrieve what the pool cannot be used for.
+ * @param p Pool pointer
+ * @return bitmap of actions not supported.
+ */
+uint64_t LSM_DLL_EXPORT lsm_pool_unsupported_actions_get( lsm_pool *p);
+
#ifdef __cplusplus
}
#endif
diff --git a/c_binding/include/libstoragemgmt/libstoragemgmt_types.h b/c_binding/include/libstoragemgmt/libstoragemgmt_types.h
index ec81bb9..653c1fa 100644
--- a/c_binding/include/libstoragemgmt/libstoragemgmt_types.h
+++ b/c_binding/include/libstoragemgmt/libstoragemgmt_types.h
@@ -223,6 +223,9 @@ typedef enum {
#define LSM_POOL_ELEMENT_TYPE_DELTA 0x0000000000000010
#define LSM_POOL_ELEMENT_TYPE_SYS_RESERVED 0x0000000000000400
+#define LSM_POOL_UNSUPPORTED_VOLUME_EXPAND 0x0000000000000001
+#define LSM_POOL_UNSUPPORTED_VOLUME_SHRINK 0x0000000000000002
+
typedef enum {
LSM_TARGET_PORT_TYPE_UNKNOWN = 0,
LSM_TARGET_PORT_TYPE_OTHER = 1,
diff --git a/c_binding/lsm_convert.cpp b/c_binding/lsm_convert.cpp
index f3693eb..7baf2e6 100644
--- a/c_binding/lsm_convert.cpp
+++ b/c_binding/lsm_convert.cpp
@@ -191,6 +191,7 @@ lsm_pool *value_to_pool(Value &pool)
rc = lsm_pool_record_alloc(i["id"].asString().c_str(),
i["name"].asString().c_str(),
i["element_type"].asUint64_t(),
+ i["unsupported_actions"].asUint64_t(),
i["total_space"].asUint64_t(),
i["free_space"].asUint64_t(),
i["status"].asUint64_t(),
@@ -209,6 +210,7 @@ Value pool_to_value(lsm_pool *pool)
p["id"] = Value(pool->id);
p["name"] = Value(pool->name);
p["element_type"] = Value(pool->element_type);
+ p["unsupported_actions"] = Value(pool->unsupported_actions);
p["total_space"] = Value(pool->total_space);
p["free_space"] = Value(pool->free_space);
p["status"] = Value(pool->status);
diff --git a/c_binding/lsm_datatypes.cpp b/c_binding/lsm_datatypes.cpp
index a0248b2..8363326 100644
--- a/c_binding/lsm_datatypes.cpp
+++ b/c_binding/lsm_datatypes.cpp
@@ -484,6 +484,7 @@ CREATE_ALLOC_ARRAY_FUNC(lsm_pool_record_array_alloc, lsm_pool *)
lsm_pool *lsm_pool_record_alloc(const char *id, const char *name,
uint64_t element_type,
+ uint64_t unsupported_actions,
uint64_t totalSpace, uint64_t freeSpace, uint64_t status,
const char* status_info,
const char *system_id, const char * plugin_data)
@@ -494,6 +495,7 @@ lsm_pool *lsm_pool_record_alloc(const char *id, const char *name,
rc->id = strdup(id);
rc->name = strdup(name);
rc->element_type = element_type;
+ rc->unsupported_actions = unsupported_actions;
rc->total_space = totalSpace;
rc->free_space = freeSpace;
rc->status = status;
@@ -525,6 +527,7 @@ lsm_pool * lsm_pool_record_copy( lsm_pool *toBeCopied)
if( LSM_IS_POOL(toBeCopied) ) {
return lsm_pool_record_alloc(toBeCopied->id, toBeCopied->name,
toBeCopied->element_type,
+ toBeCopied->unsupported_actions,
toBeCopied->total_space,
toBeCopied->free_space,
toBeCopied->status,
@@ -633,6 +636,9 @@ MEMBER_FUNC_GET(const char *, lsm_pool_plugin_data_get, lsm_pool *p,
MEMBER_FUNC_GET( uint64_t, lsm_pool_element_type_get, lsm_pool *p, p, LSM_IS_POOL,
element_type, 0)
+MEMBER_FUNC_GET( uint64_t, lsm_pool_unsupported_actions_get, lsm_pool *p, p,
+ LSM_IS_POOL, element_type, 0)
+
CREATE_ALLOC_ARRAY_FUNC(lsm_volume_record_array_alloc, lsm_volume *)
lsm_volume * lsm_volume_record_alloc(const char *id, const char *name,
diff --git a/c_binding/lsm_datatypes.hpp b/c_binding/lsm_datatypes.hpp
index 27976db..dbeaca1 100644
--- a/c_binding/lsm_datatypes.hpp
+++ b/c_binding/lsm_datatypes.hpp
@@ -81,6 +81,7 @@ struct LSM_DLL_LOCAL _lsm_pool {
char *id; /**< System wide unique identifier */
char *name; /**< Human recognizeable name */
uint64_t element_type; /**< What the pool can be used for */
+ uint64_t unsupported_actions; /**< What pool cannot be used for */
uint64_t total_space; /**< Total size */
uint64_t free_space; /**< Free space available */
uint64_t status; /**< Status of pool */
diff --git a/plugin/nstor/nstor.py b/plugin/nstor/nstor.py
index c5e3ef1..98b73be 100644
--- a/plugin/nstor/nstor.py
+++ b/plugin/nstor/nstor.py
@@ -134,6 +134,7 @@ class NexentaStor(INfs, IStorageAreaNetwork):
pools.append(Pool(pool_info['name'], pool_info['name'],
Pool.ELEMENT_TYPE_VOLUME | Pool.ELEMENT_TYPE_FS,
+ 0,
NexentaStor._to_bytes(pool_info['size']),
NexentaStor._to_bytes(pool_info['free']),
Pool.STATUS_UNKNOWN, '', self.system.id))
diff --git a/plugin/ontap/ontap.py b/plugin/ontap/ontap.py
index 5dcbcc7..02e7a33 100644
--- a/plugin/ontap/ontap.py
+++ b/plugin/ontap/ontap.py
@@ -451,7 +451,7 @@ class Ontap(IStorageAreaNetwork, INfs):
if pool_name == '/vol/vol0':
element_type |= Pool.ELEMENT_TYPE_SYS_RESERVED
- return Pool(pool_id, pool_name, element_type, total_space, free_space,
+ return Pool(pool_id, pool_name, element_type, 0, total_space, free_space,
status, status_info, system_id)
@handle_ontap_errors
diff --git a/plugin/sim/simarray.py b/plugin/sim/simarray.py
index f391681..1d5f517 100644
--- a/plugin/sim/simarray.py
+++ b/plugin/sim/simarray.py
@@ -221,9 +221,10 @@ class SimArray(object):
status = sim_pool['status']
status_info = sim_pool['status_info']
sys_id = sim_pool['sys_id']
+ unsupported_actions = sim_pool['unsupported_actions']
return Pool(pool_id, name,
Pool.ELEMENT_TYPE_VOLUME | Pool.ELEMENT_TYPE_FS,
- total_space, free_space, status,
+ unsupported_actions, total_space, free_space, status,
status_info, sys_id)
def pools(self, flags=0):
@@ -552,6 +553,8 @@ class SimData(object):
| Pool.ELEMENT_TYPE_POOL \
| Pool.ELEMENT_TYPE_VOLUME
+ SIM_DATA_POOL_UNSUPPORTED_ACTIONS = 0
+
SIM_DATA_SYS_POOL_ELEMENT_TYPE = SIM_DATA_POOL_ELEMENT_TYPE \
| Pool.ELEMENT_TYPE_SYS_RESERVED
@@ -617,6 +620,8 @@ class SimData(object):
'status_info': SimData.SIM_DATA_POOL_STATUS_INFO,
'sys_id': SimData.SIM_DATA_SYS_ID,
'element_type': SimData.SIM_DATA_SYS_POOL_ELEMENT_TYPE,
+ 'unsupported_actions': Pool.UNSUPPORTED_VOLUME_EXPAND | \
+ Pool.UNSUPPORTED_VOLUME_SHRINK
},
'POO2': {
'pool_id': 'POO2',
@@ -629,6 +634,7 @@ class SimData(object):
'status_info': SimData.SIM_DATA_POOL_STATUS_INFO,
'sys_id': SimData.SIM_DATA_SYS_ID,
'element_type': SimData.SIM_DATA_POOL_ELEMENT_TYPE,
+ 'unsupported_actions': SimData.SIM_DATA_POOL_UNSUPPORTED_ACTIONS
},
# lsm_test_aggr pool is required by test/runtest.sh
'lsm_test_aggr': {
@@ -641,6 +647,7 @@ class SimData(object):
'status_info': SimData.SIM_DATA_POOL_STATUS_INFO,
'sys_id': SimData.SIM_DATA_SYS_ID,
'element_type': SimData.SIM_DATA_POOL_ELEMENT_TYPE,
+ 'unsupported_actions': SimData.SIM_DATA_POOL_UNSUPPORTED_ACTIONS
},
}
self.vol_dict = {
@@ -701,6 +708,7 @@ class SimData(object):
'status_info': SimData.SIM_DATA_POOL_STATUS_INFO,
'sys_id': SimData.SIM_DATA_SYS_ID,
'element_type': SimData.SIM_DATA_POOL_ELEMENT_TYPE,
+ 'unsupported_actions': SimData.SIM_DATA_POOL_UNSUPPORTED_ACTIONS
}
self.tgt_dict = {
diff --git a/plugin/simc/simc_lsmplugin.c b/plugin/simc/simc_lsmplugin.c
index 7c55337..e2e28da 100644
--- a/plugin/simc/simc_lsmplugin.c
+++ b/plugin/simc/simc_lsmplugin.c
@@ -2119,10 +2119,10 @@ int load( lsm_plugin_ptr c, const char *uri, const char *password,
p = lsm_pool_record_alloc("POOL_3", "lsm_test_aggr",
LSM_POOL_ELEMENT_TYPE_FS|
- LSM_POOL_ELEMENT_TYPE_VOLUME,
+ LSM_POOL_ELEMENT_TYPE_VOLUME, 0,
UINT64_MAX, UINT64_MAX,
LSM_POOL_STATUS_OK, "",
- sys_id, NULL);
+ sys_id, 0);
if( p ) {
pd->pools = g_hash_table_new_full(g_str_hash, g_str_equal, free,
free_pool_record);
@@ -2134,7 +2134,7 @@ int load( lsm_plugin_ptr c, const char *uri, const char *password,
snprintf(name, sizeof(name), "POOL_%d", i);
p = lsm_pool_record_alloc(name, name, LSM_POOL_ELEMENT_TYPE_FS|
- LSM_POOL_ELEMENT_TYPE_VOLUME, UINT64_MAX,
+ LSM_POOL_ELEMENT_TYPE_VOLUME, 0, UINT64_MAX,
UINT64_MAX, LSM_POOL_STATUS_OK, "",
sys_id, NULL);
diff --git a/plugin/smispy/smis.py b/plugin/smispy/smis.py
index 5a7f2b2..048de69 100644
--- a/plugin/smispy/smis.py
+++ b/plugin/smispy/smis.py
@@ -255,12 +255,16 @@ class Smis(IStorageAreaNetwork):
JOB_RETRIEVE_POOL = 2
# DMTF CIM 2.37.0 experimental CIM_StoragePool['Usage']
- DMTF_POOL_USAGE_SPARE = 8
+ DMTF_POOL_USAGE_UNRESTRICTED = 2
+ DMTF_POOL_USAGE_RESERVED_FOR_SYSTEM = 3
DMTF_POOL_USAGE_DELTA = 4
+ DMTF_POOL_USAGE_SPARE = 8
# DMTF CIM 2.29.1 CIM_StorageConfigurationCapabilities
# ['SupportedStorageElementFeatures']
DMTF_SUPPORT_VOL_CREATE = 3
+ DMTF_SUPPORT_ELEMENT_EXPAND = 12
+ DMTF_SUPPORT_ELEMENT_REDUCE = 13
# DMTF CIM 2.37.0 experimental CIM_StorageConfigurationCapabilities
# ['SupportedStorageElementTypes']
@@ -1650,9 +1654,10 @@ class Smis(IStorageAreaNetwork):
(status, status_info) = DMTF.cim_pool_status_of(
cim_pool['OperationalStatus'])
- element_type = self._pool_element_type(cim_pool)
+ element_type, unsupported = self._pool_element_type(cim_pool)
- return Pool(pool_id, name, element_type, total_space, free_space,
+ return Pool(pool_id, name, element_type, unsupported,
+ total_space, free_space,
status, status_info, system_id)
@staticmethod
@@ -3171,6 +3176,7 @@ class Smis(IStorageAreaNetwork):
def _pool_element_type(self, cim_pool):
element_type = 0
+ unsupported = 0
# check whether current pool support create volume or not.
cim_sccs = self._c.Associators(
@@ -3185,10 +3191,16 @@ class Smis(IStorageAreaNetwork):
# Manipulation, Figure 9 - Capabilities Specific to a StoragePool
if len(cim_sccs) == 1:
cim_scc = cim_sccs[0]
- if 'SupportedStorageElementFeatures' in cim_scc and \
- Smis.DMTF_SUPPORT_VOL_CREATE in \
- cim_scc['SupportedStorageElementFeatures']:
- element_type = Pool.ELEMENT_TYPE_VOLUME
+ if 'SupportedStorageElementFeatures' in cim_scc:
+ supported_features = cim_scc['SupportedStorageElementFeatures']
+
+ if Smis.DMTF_SUPPORT_VOL_CREATE in supported_features:
+ element_type |= Pool.ELEMENT_TYPE_VOLUME
+ if Smis.DMTF_SUPPORT_ELEMENT_EXPAND not in supported_features:
+ unsupported |= Pool.UNSUPPORTED_VOLUME_EXPAND
+ if Smis.DMTF_SUPPORT_ELEMENT_REDUCE not in supported_features:
+ unsupported |= Pool.UNSUPPORTED_VOLUME_SHRINK
+
else:
# IBM DS 8000 does not support StorageConfigurationCapabilities
# per pool yet. They has been informed. Before fix, use a quick
@@ -3205,12 +3217,18 @@ class Smis(IStorageAreaNetwork):
element_type = Pool.ELEMENT_TYPE_VOLUME
if 'Usage' in cim_pool:
- if cim_pool['Usage'] == Smis.DMTF_POOL_USAGE_DELTA:
+ usage = cim_pool['Usage']
+
+ if usage == Smis.DMTF_POOL_USAGE_UNRESTRICTED:
+ element_type |= Pool.ELEMENT_TYPE_VOLUME
+ if usage == Smis.DMTF_POOL_USAGE_RESERVED_FOR_SYSTEM or \
+ usage > Smis.DMTF_POOL_USAGE_DELTA:
+ element_type |= Pool.ELEMENT_TYPE_SYS_RESERVED
+ if usage == Smis.DMTF_POOL_USAGE_DELTA:
+ # We blitz all the other elements types for this designation
element_type = Pool.ELEMENT_TYPE_DELTA
- if cim_pool['Usage'] == 2:
- element_type = Pool.ELEMENT_TYPE_VOLUME
- return element_type
+ return element_type, unsupported
def _profile_is_supported(self, profile_name, spec_ver, strict=False,
raise_error=False):
diff --git a/plugin/targetd/targetd.py b/plugin/targetd/targetd.py
index 989dbf5..26537a5 100644
--- a/plugin/targetd/targetd.py
+++ b/plugin/targetd/targetd.py
@@ -180,7 +180,7 @@ class TargetdStorage(IStorageAreaNetwork, INfs):
et = Pool.ELEMENT_TYPE_VOLUME
pools.append(Pool(pool['name'],
- pool['name'], et, pool['size'],
+ pool['name'], et, 0, pool['size'],
pool['free_size'], Pool.STATUS_UNKNOWN, '',
'targetd'))
return search_property(pools, search_key, search_value)
diff --git a/python_binding/lsm/_data.py b/python_binding/lsm/_data.py
index b7f3290..43614b9 100644
--- a/python_binding/lsm/_data.py
+++ b/python_binding/lsm/_data.py
@@ -308,6 +308,7 @@ class System(IData):
@default_property('system_id', doc="System identifier")
@default_property("plugin_data", doc="Plug-in private data")
@default_property("element_type", doc="What pool can be used for")
+@default_property("unsupported_actions", doc="What cannot be done with this pool")
class Pool(IData):
"""
Pool specific information
@@ -328,6 +329,10 @@ class Pool(IData):
ELEMENT_TYPE_DELTA = 1 << 4
ELEMENT_TYPE_SYS_RESERVED = 1 << 10 # Reserved for system use
+ # Unsupported actions, what pool cannot be used for
+ UNSUPPORTED_VOLUME_EXPAND = 1 << 0
+ UNSUPPORTED_VOLUME_SHRINK = 1 << 1
+
# Pool status could be any combination of these status.
STATUS_UNKNOWN = 1 << 0
STATUS_OK = 1 << 1
@@ -343,11 +348,14 @@ class Pool(IData):
STATUS_GROWING = 1 << 15
STATUS_DESTROYING = 1 << 17
- def __init__(self, _id, _name, _element_type, _total_space, _free_space,
+ def __init__(self, _id, _name, _element_type, _unsupported_actions,
+ _total_space, _free_space,
_status, _status_info, _system_id, _plugin_data=None):
self._id = _id # Identifier
self._name = _name # Human recognisable name
self._element_type = _element_type # What pool can be used to create
+ self._unsupported_actions = _unsupported_actions # What pool cannot be
+ # used for
self._total_space = _total_space # Total size
self._free_space = _free_space # Free space available
self._status = _status # Status of pool.
diff --git a/test/plugin_test.py b/test/plugin_test.py
index 042835a..75e3650 100755
--- a/test/plugin_test.py
+++ b/test/plugin_test.py
@@ -271,9 +271,11 @@ class TestPlugin(unittest.TestCase):
for p in self.pool_by_sys_id[system_id]:
# If the pool matches our criteria and min size we will consider
# it, but we will select the one with the most free space for
- # testing.
+ # testing and one that support volume expansion
if p.element_type & element_type and \
- p.free_space > mb_in_bytes(MIN_POOL_SIZE):
+ p.free_space > mb_in_bytes(MIN_POOL_SIZE) and \
+ (not p.unsupported_actions &
+ lsm.Pool.UNSUPPORTED_VOLUME_EXPAND):
if p.free_space > largest_free:
largest_free = p.free_space
rc = p
@@ -340,10 +342,10 @@ class TestPlugin(unittest.TestCase):
disks = self.c.disks()
self.assertTrue(len(disks) > 0, "We need at least 1 disk to test")
- def _volume_create(self, system_id):
+ def _volume_create(self, system_id,
+ element_type=lsm.Pool.ELEMENT_TYPE_VOLUME):
if system_id in self.pool_by_sys_id:
- p = self._get_pool_by_usage(system_id,
- lsm.Pool.ELEMENT_TYPE_VOLUME)
+ p = self._get_pool_by_usage(system_id, element_type)
self.assertTrue(p is not None, "Unable to find a suitable pool")
diff --git a/tools/lsmcli/data_display.py b/tools/lsmcli/data_display.py
index 8fab818..080f6fa 100644
--- a/tools/lsmcli/data_display.py
+++ b/tools/lsmcli/data_display.py
@@ -52,7 +52,8 @@ def _bit_map_to_str(bit_map, conv_dict):
for cur_enum in conv_dict.keys():
if cur_enum & bit_map:
rc.append(conv_dict[cur_enum])
- if len(rc) == 0:
+ # If there are no bits set we really don't need a string
+ if bit_map != 0 and len(rc) == 0:
return 'Unknown(%s)' % hex(bit_map)
return BIT_MAP_STRING_SPLITTER.join(rc)
@@ -118,11 +119,20 @@ _POOL_ELEMENT_TYPE_CONV = {
Pool.ELEMENT_TYPE_DELTA: "DELTA",
}
+_POOL_UNSUPPORTED_ACTION_CONV = {
+ Pool.UNSUPPORTED_VOLUME_EXPAND: "Volume expand",
+ Pool.UNSUPPORTED_VOLUME_SHRINK: "Volume shrink"
+}
+
def pool_element_type_to_str(element_type):
return _bit_map_to_str(element_type, _POOL_ELEMENT_TYPE_CONV)
+def pool_unsupported_actions_to_str(unsupported_action):
+ return _bit_map_to_str(unsupported_action, _POOL_UNSUPPORTED_ACTION_CONV)
+
+
_VOL_PROVISION_CONV = {
Volume.PROVISION_DEFAULT: 'DEFAULT',
Volume.PROVISION_FULL: 'FULL',
@@ -299,6 +309,7 @@ class DisplayData(object):
POOL_MAN_HEADER['id'] = 'ID'
POOL_MAN_HEADER['name'] = 'Name'
POOL_MAN_HEADER['element_type'] = 'Element type'
+ POOL_MAN_HEADER['unsupported_actions'] = 'Does not support'
POOL_MAN_HEADER['total_space'] = 'Total Space'
POOL_MAN_HEADER['free_space'] = 'Free Space'
POOL_MAN_HEADER['status'] = 'Status'
@@ -310,6 +321,7 @@ class DisplayData(object):
POOL_VALUE_CONV_ENUM = {
'status': pool_status_to_str,
'element_type': pool_element_type_to_str,
+ 'unsupported_actions': pool_unsupported_actions_to_str
}
POOL_VALUE_CONV_HUMAN = ['total_space', 'free_space']
--
1.8.2.1
1.8.2.1