* New methods:
For detail information, please refer to docstring of python methods.
* Python:
* lsm.Client.volume_raid_create_cap_get(self, system,
flags=lsm.Client.FLAG_RSVD)
Query supported RAID types and strip sizes of volume_create_raid().
* lsm.Client.volume_raid_create(self, name, raid_type, disks,
strip_size,
flags=lsm.Client.FLAG_RSVD)
Create a disk RAID pool and allocate its full space to single
volume.
* C user API:
* int lsm_volume_create_raid_cap_get(
lsm_connect *c, lsm_system *system,
uint32_t **supported_raid_types,
uint32_t *supported_raid_type_count,
uint32_t **supported_strip_sizes,
uint32_t *supported_strip_size_count,
lsm_flag flags);
* int lsm_volume_create_raid(
lsm_connect *c, const char *name, lsm_volume_raid_type raid_type,
lsm_disk *disks[], uint32_t disk_count, uint32_t strip_size,
lsm_volume **new_volume, lsm_flag flags);
* C plugin interfaces:
* typedef int (*lsm_plug_volume_create_raid_cap_get)(
lsm_plugin_ptr c, lsm_system *system,
uint32_t **supported_raid_types,
uint32_t *supported_raid_type_count,
uint32_t **supported_strip_sizes, uint32_t
*supported_strip_size_count, lsm_flag flags)
* typedef int (*lsm_plug_volume_create_raid)(
lsm_plugin_ptr c, const char *name,
lsm_volume_raid_type raid_type, lsm_disk *disks[], uint32_t
disk_count, uint32_t strip_size, lsm_volume **new_volume,
lsm_flag flags);
* Added two above into 'lsm_ops_v1_2' struct.
* C internal functions for converting C uint32 array to C++ Value:
* values_to_uint32_array(
Value &value, uint32_t **uint32_array, uint32_t *count)
* uint32_array_to_value(
uint32_t *uint32_array, uint32_t count)
* New capability:
* Python: lsm.Capabilities.VOLUME_CREATE_RAID
* C: LSM_CAP_VOLUME_CREATE_RAID
* New errors:
* Python: lsm.ErrorNumber.NOT_FOUND_DISK, lsm.ErrorNumber.DISK_NOT_FREE
* C: LSM_ERR_NOT_FOUND_DISK, LSM_ERR_DISK_NOT_FREE
* Design notes:
* Why not create pool only and allocate volume from it?
Neither HP Smart Array nor LSI MegaRAID support this.
Both require at least one volume on any pool(RAID group) and
pool(RAID group) only created when creating volume.
This is also the root reason that this method is dedicate for
hardware RAID cards, not for SAN or NAS.
* Why not allowing create multiple volumes but use single volume
consuming all space?
Even both vendors above support creating creating multiple volumes
in simple command, but it will be complex design API and many new
errors. In my humble options, most use case is to create single
volume and let OS create partitions on it.
* Why not store supported RAID type and stripe size in existing
lsm.Client.capabilities() call?
RAID type could be stored in capabilities(), but both plugin
implementation and user code has to do a capability to raid type
conversion. The strip size is number, even two vendors mentioned above
are supporting the same list of strip size, but there is no reason
create this limitation, again, conversion is also required for
capability to strip size integer if saving it in capabilities().
* Why not storing supported RAID type returned by
volume_raid_create_cap_get() in bitmap?
A conversion is require is do so. Just want to make plugin and
API user life easier.
* Why strip size is mandatory argument and where is strip size change
method?
Changing strip size after volume creation will normally take a long
time for data migration. We will not introduce strip size change
method without convincing user case.
Changes in V2:
* Rebased on pool_raid_info->pool_member_info rename changes.
* Fix 'comparison between signed and unsigned integer' in
lsm_volume_create_raid() of lsm_mgmt.cpp.
* Initialize pointers in handle_volume_create_raid_cap_get() of
lsm_plugin_ipc.cpp.
Changes in V4:
* Use 'volume_raid_create' instead:
* lsm.Client.volume_raid_create()
* lsm.Client.volume_raid_create_cap_get()
* lsm_volume_raid_create_cap_get()
* lsm_volume_raid_create()
* lsm_plug_volume_raid_create()
* lsm_plug_volume_raid_create_cap_get()
* Use this capability instead:
* LSM_CAP_VOLUME_RAID_CREATE/lsm.Capabilities.VOLUME_RAID_CREATE
* Changed method description to 'Create a disk RAID pool and allocate entire
full space to new volume."
* Free member and set output values to sane if error occurred in
lsm_volume_raid_create_cap_get() of lsm_mgmt.cpp.
* Only free uint32 array if not NULL in handle_volume_create_raid_cap_get()
of lsm_plugin_ipc.cpp.
* Free lsm_sys memory before quit in handle_volume_create_raid_cap_get() of
lsm_plugin_ipc.cpp.
* Fix incorrect strip_size data conversion from JSON to C in
handle_volume_create_raid() of lsm_plugin_ipc.cpp.
* Free lsm_volume memory before quit in handle_volume_create_raid() of
lsm_plugin_ipc.cpp.
* Updated docstring of lsm.Client.volume_raid_create_cap_get() by
removing incorrect RAID types(RAID 15/16/51/61) as no plugin support them
yet.
* Updated docstring of lsm.Client.volume_raid_create() by removing incorrect
capabilities.
* Updated docstring of lsm.Client.volume_raid_create() by removing
NAME_CONFLICT error of duplicate call. Duplicate call should always
raise DISK_NOT_FREE error.
* Updated docstring of lsm.Client.volume_raid_create() by mentioning
the name of new pool should be automatically chose by plugin.
Signed-off-by: Gris Ge <***@redhat.com>
---
c_binding/include/libstoragemgmt/libstoragemgmt.h | 62 +++++++
.../libstoragemgmt/libstoragemgmt_capabilities.h | 1 +
.../include/libstoragemgmt/libstoragemgmt_error.h | 2 +
.../libstoragemgmt/libstoragemgmt_plug_interface.h | 57 +++++++
.../include/libstoragemgmt/libstoragemgmt_types.h | 3 +
c_binding/lsm_convert.cpp | 41 +++++
c_binding/lsm_convert.hpp | 12 ++
c_binding/lsm_mgmt.cpp | 128 ++++++++++++++
c_binding/lsm_plugin_ipc.cpp | 96 ++++++++++-
python_binding/lsm/_client.py | 187 +++++++++++++++++++++
python_binding/lsm/_common.py | 3 +
python_binding/lsm/_data.py | 3 +
12 files changed, 594 insertions(+), 1 deletion(-)
diff --git a/c_binding/include/libstoragemgmt/libstoragemgmt.h b/c_binding/include/libstoragemgmt/libstoragemgmt.h
index 85022b4..869d5fd 100644
--- a/c_binding/include/libstoragemgmt/libstoragemgmt.h
+++ b/c_binding/include/libstoragemgmt/libstoragemgmt.h
@@ -891,6 +891,68 @@ int LSM_DLL_EXPORT lsm_pool_member_info(
lsm_pool_member_type *member_type, lsm_string_list **member_ids,
lsm_flag flags);
+/**
+ * Query all supported RAID types and strip sizes which could be used
+ * in lsm_volume_raid_create() functions.
+ * New in version 1.2, only available for hardware RAID cards.
+ * @param[in] c Valid connection
+ * @param[in] system
+ * The lsm_sys type.
+ * @param[out] supported_raid_types
+ * The pointer of uint32_t array. Containing
+ * lsm_volume_raid_type values.
+ * You need to free this memory by yourself.
+ * @param[out] supported_raid_type_count
+ * The pointer of uint32_t. Indicate the item count of
+ * supported_raid_types array.
+ * @param[out] supported_strip_sizes
+ * The pointer of uint32_t array. Containing
+ * all supported strip sizes.
+ * You need to free this memory by yourself.
+ * @param[out] supported_strip_size_count
+ * The pointer of uint32_t. Indicate the item count of
+ * supported_strip_sizes array.
+ * @param[in] flags Reserved, set to 0
+ * @return LSM_ERR_OK on success else error reason.
+ */
+int LSM_DLL_EXPORT lsm_volume_raid_create_cap_get(
+ lsm_connect *c, lsm_system *system,
+ uint32_t **supported_raid_types, uint32_t *supported_raid_type_count,
+ uint32_t **supported_strip_sizes, uint32_t *supported_strip_size_count,
+ lsm_flag flags);
+
+/**
+ * Create a disk RAID pool and allocate entire full space to new volume.
+ * New in version 1.2, only available for hardware RAID cards.
+ * @param[in] c Valid connection
+ * @param[in] name String. Name for the new volume. It might be ignored or
+ * altered on some hardwardware raid cards in order to fit
+ * their limitation.
+ * @param[in] raid_type
+ * Enum of lsm_volume_raid_type. Please refer to the returns
+ * of lsm_volume_raid_create_cap_get() function for
+ * supported strip sizes.
+ * @param[in] disks
+ * An array of lsm_disk types
+ * @param[in] disk_count
+ * The count of lsm_disk in 'disks' argument.
+ * Count starts with 1.
+ * @param[in] strip_size
+ * uint32_t. The strip size in bytes. Please refer to
+ * the returns of lsm_volume_raid_create_cap_get() function
+ * for supported strip sizes.
+ * @param[out] new_volume
+ * Newly created volume, Pointer to the lsm_volume type
+ * pointer.
+ * @param[in] flags Reserved, set to 0
+ * @return LSM_ERR_OK on success else error reason.
+ */
+int LSM_DLL_EXPORT lsm_volume_raid_create(
+ lsm_connect *c, const char *name, lsm_volume_raid_type raid_type,
+ lsm_disk *disks[], uint32_t disk_count,
+ uint32_t strip_size, lsm_volume **new_volume,
+ lsm_flag flags);
+
#ifdef __cplusplus
}
#endif
diff --git a/c_binding/include/libstoragemgmt/libstoragemgmt_capabilities.h b/c_binding/include/libstoragemgmt/libstoragemgmt_capabilities.h
index 943f4a4..07bf8b0 100644
--- a/c_binding/include/libstoragemgmt/libstoragemgmt_capabilities.h
+++ b/c_binding/include/libstoragemgmt/libstoragemgmt_capabilities.h
@@ -117,6 +117,7 @@ typedef enum {
LSM_CAP_POOL_MEMBER_INFO = 221,
/**^ Query pool member information */
+ LSM_CAP_VOLUME_RAID_CREATE = 222,
} lsm_capability_type;
/**
diff --git a/c_binding/include/libstoragemgmt/libstoragemgmt_error.h b/c_binding/include/libstoragemgmt/libstoragemgmt_error.h
index 0b28ddc..29c460a 100644
--- a/c_binding/include/libstoragemgmt/libstoragemgmt_error.h
+++ b/c_binding/include/libstoragemgmt/libstoragemgmt_error.h
@@ -63,6 +63,7 @@ typedef enum {
LSM_ERR_NOT_FOUND_VOLUME = 205, /**< Specified volume not found */
LSM_ERR_NOT_FOUND_NFS_EXPORT = 206, /**< NFS export not found */
LSM_ERR_NOT_FOUND_SYSTEM = 208, /**< System not found */
+ LSM_ERR_NOT_FOUND_DISK = 209,
LSM_ERR_NOT_LICENSED = 226, /**< Need license for feature */
@@ -90,6 +91,7 @@ typedef enum {
LSM_ERR_EMPTY_ACCESS_GROUP = 511,
LSM_ERR_POOL_NOT_READY = 512,
+ LSM_ERR_DISK_NOT_FREE = 513,
} lsm_error_number;
diff --git a/c_binding/include/libstoragemgmt/libstoragemgmt_plug_interface.h b/c_binding/include/libstoragemgmt/libstoragemgmt_plug_interface.h
index cdc8dc9..460054d 100644
--- a/c_binding/include/libstoragemgmt/libstoragemgmt_plug_interface.h
+++ b/c_binding/include/libstoragemgmt/libstoragemgmt_plug_interface.h
@@ -853,6 +853,61 @@ typedef int (*lsm_plug_pool_member_info)(
lsm_pool_member_type *member_type, lsm_string_list **member_ids,
lsm_flag flags);
+/**
+ * Query all supported RAID types and strip sizes which could be used
+ * in lsm_volume_raid_create() functions.
+ * New in version 1.2, only available for hardware RAID cards.
+ * @param[in] c Valid lsm plug-in pointer
+ * @param[in] system
+ * The lsm_sys type.
+ * @param[out] supported_raid_types
+ * The pointer of uint32_t array. Containing
+ * lsm_volume_raid_type values.
+ * @param[out] supported_raid_type_count
+ * The pointer of uint32_t. Indicate the item count of
+ * supported_raid_types array.
+ * @param[out] supported_strip_sizes
+ * The pointer of uint32_t array. Containing
+ * all supported strip sizes.
+ * @param[out] supported_strip_size_count
+ * The pointer of uint32_t. Indicate the item count of
+ * supported_strip_sizes array.
+ * @param[in] flags Reserved, set to 0
+ * @return LSM_ERR_OK on success else error reason.
+ */
+typedef int (*lsm_plug_volume_raid_create_cap_get)(
+ lsm_plugin_ptr c, lsm_system *system,
+ uint32_t **supported_raid_types, uint32_t *supported_raid_type_count,
+ uint32_t **supported_strip_sizes, uint32_t *supported_strip_size_count,
+ lsm_flag flags);
+
+/**
+ * Create a disk RAID pool and allocate entire full space to new volume.
+ * New in version 1.2, only available for hardware RAID cards.
+ * @param[in] c Valid lsm plug-in pointer
+ * @param[in] name String. Name for the new volume. It might be ignored or
+ * altered on some hardwardware raid cards in order to fit
+ * their limitation.
+ * @param[in] raid_type
+ * Enum of lsm_volume_raid_type.
+ * @param[in] disks
+ * An array of lsm_disk types
+ * @param[in] disk_count
+ * The count of lsm_disk in 'disks' argument.
+ * @param[in] strip_size
+ * uint32_t. The strip size in bytes.
+ * @param[out] new_volume
+ * Newly created volume, Pointer to the lsm_volume type
+ * pointer.
+ * @param[in] flags Reserved, set to 0
+ * @return LSM_ERR_OK on success else error reason.
+ */
+typedef int (*lsm_plug_volume_raid_create)(
+ lsm_plugin_ptr c, const char *name, lsm_volume_raid_type raid_type,
+ lsm_disk *disks[], uint32_t disk_count,
+ uint32_t strip_size, lsm_volume **new_volume,
+ lsm_flag flags);
+
/** \struct lsm_ops_v1_2
* \brief Functions added in version 1.2
* NOTE: This structure will change during the developement util version 1.2
@@ -862,6 +917,8 @@ struct lsm_ops_v1_2 {
lsm_plug_volume_raid_info vol_raid_info;
/**^ Query volume RAID information*/
lsm_plug_pool_member_info pool_member_info;
+ lsm_plug_volume_raid_create_cap_get vol_create_raid_cap_get;
+ lsm_plug_volume_raid_create vol_create_raid;
};
/**
diff --git a/c_binding/include/libstoragemgmt/libstoragemgmt_types.h b/c_binding/include/libstoragemgmt/libstoragemgmt_types.h
index 115ec5a..667c320 100644
--- a/c_binding/include/libstoragemgmt/libstoragemgmt_types.h
+++ b/c_binding/include/libstoragemgmt/libstoragemgmt_types.h
@@ -297,6 +297,9 @@ typedef enum {
LSM_TARGET_PORT_TYPE_ISCSI = 4
} lsm_target_port_type;
+#define LSM_VOLUME_VCR_STRIP_SIZE_DEFAULT 0
+/** ^ Plugin and hardware RAID will use their default strip size */
+
#ifdef __cplusplus
}
#endif
diff --git a/c_binding/lsm_convert.cpp b/c_binding/lsm_convert.cpp
index 7baf2e6..9b799ab 100644
--- a/c_binding/lsm_convert.cpp
+++ b/c_binding/lsm_convert.cpp
@@ -617,3 +617,44 @@ Value target_port_to_value(lsm_target_port *tp)
}
return Value();
}
+
+int values_to_uint32_array(
+ Value &value, uint32_t **uint32_array, uint32_t *count)
+{
+ int rc = LSM_ERR_OK;
+ try {
+ std::vector<Value> data = value.asArray();
+ *count = data.size();
+ if (*count){
+ *uint32_array = (uint32_t *)malloc(sizeof(uint32_t) * *count);
+ if (*uint32_array){
+ uint32_t i;
+ for( i = 0; i < *count; i++ ){
+ (*uint32_array)[i] = data[i].asUint32_t();
+ }
+ }else{
+ rc = LSM_ERR_NO_MEMORY;
+ }
+ }
+ } catch( const ValueException &ve) {
+ if( *count ) {
+ free(*uint32_array);
+ *uint32_array = NULL;
+ *count = 0;
+ }
+ rc = LSM_ERR_LIB_BUG;
+ }
+ return rc;
+}
+
+Value uint32_array_to_value(uint32_t *uint32_array, uint32_t count)
+{
+ std::vector<Value> rc;
+ if( uint32_array && count ) {
+ uint32_t i;
+ for( i = 0; i < count; i++ ) {
+ rc.push_back(uint32_array[i]);
+ }
+ }
+ return rc;
+}
diff --git a/c_binding/lsm_convert.hpp b/c_binding/lsm_convert.hpp
index fe1e91d..907a229 100644
--- a/c_binding/lsm_convert.hpp
+++ b/c_binding/lsm_convert.hpp
@@ -284,4 +284,16 @@ lsm_target_port LSM_DLL_LOCAL *value_to_target_port(Value &tp);
*/
Value LSM_DLL_LOCAL target_port_to_value(lsm_target_port *tp);
+/**
+ * Converts a value to array of uint32.
+ */
+int LSM_DLL_LOCAL values_to_uint32_array(
+ Value &value, uint32_t **uint32_array, uint32_t *count);
+
+/**
+ * Converts an array of uint32 to a value.
+ */
+Value LSM_DLL_LOCAL uint32_array_to_value(
+ uint32_t *uint32_array, uint32_t count);
+
#endif
diff --git a/c_binding/lsm_mgmt.cpp b/c_binding/lsm_mgmt.cpp
index 7469127..d57edcc 100644
--- a/c_binding/lsm_mgmt.cpp
+++ b/c_binding/lsm_mgmt.cpp
@@ -2268,3 +2268,131 @@ int lsm_nfs_export_delete( lsm_connect *c, lsm_nfs_export *e, lsm_flag flags)
int rc = rpc(c, "export_remove", parameters, response);
return rc;
}
+
+int lsm_volume_raid_create_cap_get(
+ lsm_connect *c, lsm_system *system,
+ uint32_t **supported_raid_types, uint32_t *supported_raid_type_count,
+ uint32_t **supported_strip_sizes, uint32_t *supported_strip_size_count,
+ lsm_flag flags)
+{
+ CONN_SETUP(c);
+
+ if( !supported_raid_types || !supported_raid_type_count ||
+ !supported_strip_sizes || !supported_strip_size_count) {
+ return LSM_ERR_INVALID_ARGUMENT;
+ }
+
+ std::map<std::string, Value> p;
+ p["system"] = system_to_value(system);
+ p["flags"] = Value(flags);
+
+ Value parameters(p);
+ Value response;
+
+ int rc = rpc(c, "volume_raid_create_cap_get", parameters, response);
+ try {
+ std::vector<Value> j = response.asArray();
+
+ rc = values_to_uint32_array(
+ j[0], supported_raid_types, supported_raid_type_count);
+
+ if( rc != LSM_ERR_OK ){
+ *supported_raid_types = NULL;
+ *supported_raid_type_count = 0;
+ *supported_strip_sizes = NULL;
+ *supported_strip_size_count = 0;
+ return rc;
+ }
+
+ rc = values_to_uint32_array(
+ j[1], supported_strip_sizes, supported_strip_size_count);
+ if( rc != LSM_ERR_OK ){
+ free(*supported_raid_types);
+ *supported_raid_types = NULL;
+ *supported_raid_type_count = 0;
+ *supported_strip_sizes = NULL;
+ *supported_strip_size_count = 0;
+ }
+ } catch( const ValueException &ve ) {
+ rc = logException(c, LSM_ERR_LIB_BUG, "Unexpected type",
+ ve.what());
+ }
+ return rc;
+}
+
+int lsm_volume_raid_create(
+ lsm_connect *c, const char *name, lsm_volume_raid_type raid_type,
+ lsm_disk *disks[], uint32_t disk_count,
+ uint32_t strip_size, lsm_volume **new_volume,
+ lsm_flag flags)
+{
+ CONN_SETUP(c);
+
+ if (disk_count == 0){
+ return logException(
+ c, LSM_ERR_INVALID_ARGUMENT, "Require at least one disks", NULL);
+ }
+
+ if (raid_type == LSM_VOLUME_RAID_TYPE_RAID1 && disk_count != 2){
+ return logException(
+ c, LSM_ERR_INVALID_ARGUMENT, "RAID 1 only allows two disks", NULL);
+ }
+
+ if (raid_type == LSM_VOLUME_RAID_TYPE_RAID5 && disk_count < 3){
+ return logException(
+ c, LSM_ERR_INVALID_ARGUMENT, "RAID 5 require 3 or more disks",
+ NULL);
+ }
+
+ if (raid_type == LSM_VOLUME_RAID_TYPE_RAID6 && disk_count < 4){
+ return logException(
+ c, LSM_ERR_INVALID_ARGUMENT, "RAID 5 require 4 or more disks",
+ NULL);
+ }
+
+ if ( disk_count % 2 ){
+ if (raid_type == LSM_VOLUME_RAID_TYPE_RAID10 && disk_count < 4){
+ return logException(
+ c, LSM_ERR_INVALID_ARGUMENT,
+ "RAID 10 require even disks count and 4 or more disks",
+ NULL);
+ }
+ if (raid_type == LSM_VOLUME_RAID_TYPE_RAID50 && disk_count < 6){
+ return logException(
+ c, LSM_ERR_INVALID_ARGUMENT,
+ "RAID 50 require even disks count and 6 or more disks",
+ NULL);
+ }
+ if (raid_type == LSM_VOLUME_RAID_TYPE_RAID60 && disk_count < 8){
+ return logException(
+ c, LSM_ERR_INVALID_ARGUMENT,
+ "RAID 60 require even disks count and 8 or more disks",
+ NULL);
+ }
+ }
+
+ if (CHECK_RP(new_volume)){
+ return LSM_ERR_INVALID_ARGUMENT;
+ }
+
+ std::map<std::string, Value> p;
+ p["name"] = Value(name);
+ p["raid_type"] = Value((int32_t)raid_type);
+ p["strip_size"] = Value((int32_t)strip_size);
+ p["flags"] = Value(flags);
+ std::vector<Value> disks_value;
+ for (uint32_t i = 0; i < disk_count; i++){
+ disks_value.push_back(disk_to_value(disks[i]));
+ }
+ p["disks"] = disks_value;
+
+ Value parameters(p);
+ Value response;
+
+ int rc = rpc(c, "volume_raid_create", parameters, response);
+ if( LSM_ERR_OK == rc ) {
+ *new_volume = value_to_volume(response);
+ }
+ return rc;
+
+}
diff --git a/c_binding/lsm_plugin_ipc.cpp b/c_binding/lsm_plugin_ipc.cpp
index 89b7674..b4d7982 100644
--- a/c_binding/lsm_plugin_ipc.cpp
+++ b/c_binding/lsm_plugin_ipc.cpp
@@ -2200,6 +2200,98 @@ static int iscsi_chap(lsm_plugin_ptr p, Value ¶ms, Value &response)
}
return rc;
}
+static int handle_volume_raid_create_cap_get(
+ lsm_plugin_ptr p, Value ¶ms, Value &response)
+{
+ int rc = LSM_ERR_NO_SUPPORT;
+ if( p && p->ops_v1_2 && p->ops_v1_2->vol_create_raid_cap_get ) {
+ Value v_system = params["system"];
+
+ if( IS_CLASS_SYSTEM(v_system) &&
+ LSM_FLAG_EXPECTED_TYPE(params) ) {
+ lsm_system *sys = value_to_system(v_system);
+
+ uint32_t *supported_raid_types = NULL;
+ uint32_t supported_raid_type_count = 0;
+
+ uint32_t *supported_strip_sizes = NULL;
+ uint32_t supported_strip_size_count = 0;
+
+ rc = p->ops_v1_2->vol_create_raid_cap_get(
+ p, sys, &supported_raid_types, &supported_raid_type_count,
+ &supported_strip_sizes, &supported_strip_size_count,
+ LSM_FLAG_GET_VALUE(params));
+
+ if( LSM_ERR_OK == rc ) {
+ std::vector<Value> result;
+ result.push_back(
+ uint32_array_to_value(
+ supported_raid_types, supported_raid_type_count));
+ result.push_back(
+ uint32_array_to_value(
+ supported_strip_sizes, supported_strip_size_count));
+ response = Value(result);
+ free(supported_raid_types);
+ free(supported_strip_sizes);
+ }
+
+ lsm_system_record_free(sys);
+
+ } else {
+ rc = LSM_ERR_TRANSPORT_INVALID_ARG;
+ }
+ }
+ return rc;
+
+}
+
+static int handle_volume_raid_create(
+ lsm_plugin_ptr p, Value ¶ms, Value &response)
+{
+ int rc = LSM_ERR_NO_SUPPORT;
+ if( p && p->ops_v1_2 && p->ops_v1_2->vol_create_raid ) {
+ Value v_name = params["name"];
+ Value v_raid_type = params["raid_type"];
+ Value v_strip_size = params["strip_size"];
+ Value v_disks = params["disks"];
+
+ if( Value::string_t == v_name.valueType() &&
+ Value::numeric_t == v_raid_type.valueType() &&
+ Value::numeric_t == v_strip_size.valueType() &&
+ Value::array_t == v_disks.valueType() &&
+ LSM_FLAG_EXPECTED_TYPE(params) ) {
+
+ lsm_disk **disks = NULL;
+ uint32_t disk_count = 0;
+ rc = value_array_to_disks(v_disks, &disks, &disk_count);
+ if( LSM_ERR_OK != rc ) {
+ return rc;
+ }
+
+ const char *name = v_name.asC_str();
+ lsm_volume_raid_type raid_type =
+ (lsm_volume_raid_type) v_raid_type.asInt32_t();
+ uint32_t strip_size = v_strip_size.asUint32_t();
+
+ lsm_volume *new_vol = NULL;
+
+ rc = p->ops_v1_2->vol_create_raid(
+ p, name, raid_type, disks, disk_count, strip_size,
+ &new_vol, LSM_FLAG_GET_VALUE(params));
+
+ if( LSM_ERR_OK == rc ) {
+ response = volume_to_value(new_vol);
+ lsm_volume_record_free(new_vol);
+ }
+
+ lsm_disk_record_array_free(disks, disk_count);
+
+ } else {
+ rc = LSM_ERR_TRANSPORT_INVALID_ARG;
+ }
+ }
+ return rc;
+}
/**
* map of function pointers
@@ -2255,7 +2347,9 @@ static std::map<std::string,handler> dispatch = static_map<std::string,handler>
("volumes_accessible_by_access_group", vol_accessible_by_ag)
("volumes", handle_volumes)
("volume_raid_info", handle_volume_raid_info)
- ("pool_member_info", handle_pool_member_info);
+ ("pool_member_info", handle_pool_member_info)
+ ("volume_raid_create", handle_volume_raid_create)
+ ("volume_raid_create_cap_get", handle_volume_raid_create_cap_get);
static int process_request(lsm_plugin_ptr p, const std::string &method, Value &request,
Value &response)
diff --git a/python_binding/lsm/_client.py b/python_binding/lsm/_client.py
index f3c9e6c..16929a5 100644
--- a/python_binding/lsm/_client.py
+++ b/python_binding/lsm/_client.py
@@ -1172,3 +1172,190 @@ def pool_member_info(self, pool, flags=FLAG_RSVD):
lsm.Capabilities.POOL_MEMBER_INFO
"""
return self._tp.rpc('pool_member_info', _del_self(locals()))
+
+ @_return_requires([[int], [int]])
+ def volume_raid_create_cap_get(self, system, flags=FLAG_RSVD):
+ """
+ lsm.Client.volume_raid_create_cap_get(
+ self, system, flags=lsm.Client.FLAG_RSVD)
+
+ Version:
+ 1.2
+ Usage:
+ This method is dedicated to local hardware RAID cards.
+ Query out all supported RAID types and strip sizes which could
+ be used by lsm.Client.volume_raid_create() method.
+ Parameters:
+ system (lsm.System)
+ Instance of lsm.System
+ flags (int)
+ Optional. Reserved for future use.
+ Should be set as lsm.Client.FLAG_RSVD.
+ Returns:
+ [raid_types, strip_sizes]
+ raid_types ([int])
+ List of integer, possible values are:
+ Volume.RAID_TYPE_RAID0
+ Volume.RAID_TYPE_RAID1
+ Volume.RAID_TYPE_RAID5
+ Volume.RAID_TYPE_RAID6
+ Volume.RAID_TYPE_RAID10
+ Volume.RAID_TYPE_RAID50
+ Volume.RAID_TYPE_RAID60
+ strip_sizes ([int])
+ List of integer. Stripe size in bytes.
+ SpecialExceptions:
+ LsmError
+ lsm.ErrorNumber.NO_SUPPORT
+ Method not supported.
+ Sample:
+ lsm_client = lsm.Client('sim://')
+ lsm_sys = lsm_client.systems()[0]
+ disks = lsm_client.disks(
+ search_key='system_id', search_value=lsm_sys.id)
+
+ free_disks = [d for d in disks if d.status == Disk.STATUS_FREE]
+ supported_raid_types, supported_strip_sizes = \
+ lsm_client.volume_raid_create_cap_get(lsm_sys)
+ new_vol = lsm_client.volume_raid_create(
+ 'test_volume_raid_create', supported_raid_types[0],
+ free_disks, supported_strip_sizes[0])
+
+ Capability:
+ lsm.Capabilities.VOLUME_CREATE_RAID
+ This method is mandatory when volume_raid_create() is
+ supported.
+ """
+ return self._tp.rpc('volume_raid_create_cap_get', _del_self(locals()))
+
+ @_return_requires(Volume)
+ def volume_raid_create(self, name, raid_type, disks, strip_size,
+ flags=FLAG_RSVD):
+ """
+ lsm.Client.volume_raid_create(self, name, raid_type, disks,
+ strip_size, flags=lsm.Client.FLAG_RSVD)
+
+ Version:
+ 1.2
+ Usage:
+ This method is dedicated to local hardware RAID cards.
+ Create a disk RAID pool and allocate entire storage space to
+ new volume using requested volume name.
+ When dealing with RAID10, 50 or 60, the first half part of
+ 'disks' will be located in one bottom layer RAID group.
+ The new volume and new pool will created within the same system
+ of provided disks.
+ This method does not allow duplicate call, when duplicate call
+ was issued, LsmError with ErrorNumber.DISK_NOT_FREE will be raise.
+ User should check disk.status for Disk.STATUS_FREE before
+ invoking this method.
+ Parameters:
+ name (string)
+ The name for new volume.
+ The requested volume name might be ignored due to restriction
+ of hardware RAID vendors.
+ The pool name will be automatically choosed by plugin.
+ raid_type (int)
+ The RAID type for the RAID group, possible values are:
+ Volume.RAID_TYPE_RAID0
+ Volume.RAID_TYPE_RAID1
+ Volume.RAID_TYPE_RAID5
+ Volume.RAID_TYPE_RAID6
+ Volume.RAID_TYPE_RAID10
+ Volume.RAID_TYPE_RAID15
+ Volume.RAID_TYPE_RAID16
+ Volume.RAID_TYPE_RAID50
+ Please check volume_raid_create_cap_get() returns to get
+ supported all raid types of current hardware RAID card.
+ disks ([lsm.Disks,])
+ A list of lsm.Disk objects. Free disks used for new RAID group.
+ strip_size (int)
+ The size in bytes of strip.
+ When setting strip_size to Volume.VCR_STRIP_SIZE_DEFAULT, it
+ allow hardware RAID cards to choose their default value.
+ Please use volume_raid_create_cap_get() method to get all
+ supported strip size of current hardware RAID card.
+ The Volume.VCR_STRIP_SIZE_DEFAULT is always supported when
+ lsm.Capabilities.VOLUME_CREATE_RAID is supported.
+ flags (int)
+ Optional. Reserved for future use.
+ Should be set as lsm.Client.FLAG_RSVD.
+ Returns:
+ lsm.Volume
+ The lsm.Volume object for newly created volume.
+ SpecialExceptions:
+ LsmError
+ lsm.ErrorNumber.NO_SUPPORT
+ Method not supported or RAID type not supported.
+ lsm.ErrorNumber.DISK_NOT_FREE
+ Disk is not in Disk.STATUS_FREE status.
+ lsm.ErrorNumber.NOT_FOUND_DISK
+ Disk not found
+ lsm.ErrorNumber.INVALID_ARGUMENT
+ 1. Invalid input argument data.
+ 2. Disks are not from the same system.
+ 3. Disks are not from the same enclosure.
+ 4. Invalid strip_size.
+ 5. Disk count are meet the minimum requirement:
+ RAID1: len(disks) == 2
+ RAID5: len(disks) >= 3
+ RAID6: len(disks) >= 4
+ RAID10: len(disks) % 2 == 0 and len(disks) >= 4
+ RAID50: len(disks) % 2 == 0 and len(disks) >= 6
+ RAID60: len(disks) % 2 == 0 and len(disks) >= 8
+ lsm.ErrorNumber.NAME_CONFLICT
+ Requested name is already be used by other volume.
+ Sample:
+ lsm_client = lsm.Client('sim://')
+ disks = lsm_client.disks()
+ free_disks = [d for d in disks if d.status == Disk.STATUS_FREE]
+ new_vol = lsm_client.volume_raid_create(
+ 'raid0_vol1', Volume.RAID_TYPE_RAID0, free_disks)
+ Capability:
+ lsm.Capabilities.VOLUME_CREATE_RAID
+ Indicate current system support volume_raid_create() method.
+ At least one RAID type should be supported.
+ The strip_size == Volume.VCR_STRIP_SIZE_DEFAULT is supported.
+ """
+ if len(disks) == 0:
+ raise LsmError(
+ ErrorNumber.INVALID_ARGUMENT,
+ "Illegal input disks argument: no disk included")
+
+ if raid_type == Volume.RAID_TYPE_RAID1 and len(disks) != 2:
+ raise LsmError(
+ ErrorNumber.INVALID_ARGUMENT,
+ "Illegal input disks argument: RAID 1 only allow 2 disks")
+
+ if raid_type == Volume.RAID_TYPE_RAID5 and len(disks) < 3:
+ raise LsmError(
+ ErrorNumber.INVALID_ARGUMENT,
+ "Illegal input disks argument: RAID 5 require 3 or more disks")
+
+ if raid_type == Volume.RAID_TYPE_RAID6 and len(disks) < 4:
+ raise LsmError(
+ ErrorNumber.INVALID_ARGUMENT,
+ "Illegal input disks argument: RAID 6 require 4 or more disks")
+
+ if raid_type == Volume.RAID_TYPE_RAID10:
+ if len(disks) % 2 or len(disks) < 4:
+ raise LsmError(
+ ErrorNumber.INVALID_ARGUMENT,
+ "Illegal input disks argument: "
+ "RAID 10 require even disks count and 4 or more disks")
+
+ if raid_type == Volume.RAID_TYPE_RAID50:
+ if len(disks) % 2 or len(disks) < 6:
+ raise LsmError(
+ ErrorNumber.INVALID_ARGUMENT,
+ "Illegal input disks argument: "
+ "RAID 50 require even disks count and 6 or more disks")
+
+ if raid_type == Volume.RAID_TYPE_RAID60:
+ if len(disks) % 2 or len(disks) < 8:
+ raise LsmError(
+ ErrorNumber.INVALID_ARGUMENT,
+ "Illegal input disks argument: "
+ "RAID 60 require even disks count and 8 or more disks")
+
+ return self._tp.rpc('volume_raid_create', _del_self(locals()))
diff --git a/python_binding/lsm/_common.py b/python_binding/lsm/_common.py
index 4c87661..be0c734 100644
--- a/python_binding/lsm/_common.py
+++ b/python_binding/lsm/_common.py
@@ -447,6 +447,7 @@ class ErrorNumber(object):
NOT_FOUND_VOLUME = 205
NOT_FOUND_NFS_EXPORT = 206
NOT_FOUND_SYSTEM = 208
+ NOT_FOUND_DISK = 209
NOT_LICENSED = 226
@@ -478,6 +479,8 @@ class ErrorNumber(object):
POOL_NOT_READY = 512 # Pool is not ready for create/resize/etc
+ DISK_NOT_FREE = 513 # Disk is not in DISK.STATUS_FREE status.
+
_LOCALS = locals()
@staticmethod
diff --git a/python_binding/lsm/_data.py b/python_binding/lsm/_data.py
index 2f42eaf..0e16311 100644
--- a/python_binding/lsm/_data.py
+++ b/python_binding/lsm/_data.py
@@ -306,6 +306,8 @@ class Volume(IData):
MIN_IO_SIZE_UNKNOWN = 0
OPT_IO_SIZE_UNKNOWN = 0
+ VCR_STRIP_SIZE_DEFAULT = 0
+
def __init__(self, _id, _name, _vpd83, _block_size, _num_of_blocks,
_admin_state, _system_id, _pool_id, _plugin_data=None):
self._id = _id # Identifier
@@ -760,6 +762,7 @@ class Capabilities(IData):
DISKS = 220
POOL_MEMBER_INFO = 221
+ VOLUME_RAID_CREATE = 222
def _to_dict(self):
return {'class': self.__class__.__name__,
--
1.8.3.1