* New commands:
* volume-create-raid
Create RAID group and allocate all space to single new volume.
* volume-create-raid-cap
Query supported RAID types and strip sizes of volume-create-raid
command.
* Manpage updated.
Changes in V3:
* Rebased to the pool_raid_info->pool_member_info changes.
Signed-off-by: Gris Ge <fge(a)redhat.com>
---
doc/man/lsmcli.1.in | 32 +++++++++++++++++++++
tools/lsmcli/cmdline.py | 67 +++++++++++++++++++++++++++++++++++++++++++-
tools/lsmcli/data_display.py | 36 +++++++++++++++++++++++-
3 files changed, 133 insertions(+), 2 deletions(-)
diff --git a/doc/man/lsmcli.1.in b/doc/man/lsmcli.1.in
index 6faf690..05deb21 100644
--- a/doc/man/lsmcli.1.in
+++ b/doc/man/lsmcli.1.in
@@ -232,6 +232,34 @@ Optional. Provisioning type. Valid values are: DEFAULT, THIN, FULL.
Provisioning enabled volume. \fBFULL\fR means requiring a fully allocated
volume.
+.SS volume-create-raid
+Creates a volume on hardware RAID on given disks.
+.TP 15
+\fB--name\fR \fI<NAME>\fR
+Required. Volume name. Might be altered or ignored due to hardware RAID card
+vendor limitation.
+.TP
+\fB--raid-type\fR \fI<RAID_TYPE>\fR
+Required. Could be one of these values: \fBRAID0\fR, \fBRAID1\fR, \fBRAID5\fR,
+\fBRAID6\fR, \fBRAID10\fR, \fBRAID50\fR, \fBRAID60\fR. The supported RAID
+types of current RAID card could be queried via command
+"\fBvolume-create-raid-cap\fR".
+.TP
+\fB--disk\fR \fI<DISK_ID>\fR
+Required. Repeatable. The disk ID for new RAID group.
+.TP
+\fB--strip-size\fR \fI<STRIP_SIZE>\fR
+Optional. The size in bytes of strip on each disks. If not defined, will let
+hardware card to use the vendor default value. The supported stripe size of
+current RAID card could be queried via command "\fBvolume-create-raid-cap\fR".
+
+.SS volume-create-raid-cap
+Query support status of volume-create-raid command for current hardware RAID
+card.
+.TP 15
+\fB--sys\fR \fI<SYS_ID>\fR
+Required. ID of the system to query for capabilities.
+
.SS volume-delete
.TP 15
Delete a volume given its ID
@@ -586,6 +614,10 @@ Alias of 'list --type target_ports'
Alias of 'plugin-info'
.SS vc
Alias of 'volume-create'
+.SS vcr
+Alias of 'volume-create-raid'
+.SS vcrc
+Alias of 'volume-create-raid-cap'
.SS vd
Alias of 'volume-delete'
.SS vr
diff --git a/tools/lsmcli/cmdline.py b/tools/lsmcli/cmdline.py
index d26da80..42c2365 100644
--- a/tools/lsmcli/cmdline.py
+++ b/tools/lsmcli/cmdline.py
@@ -40,7 +40,7 @@
from lsm.lsmcli.data_display import (
DisplayData, PlugData, out,
vol_provision_str_to_type, vol_rep_type_str_to_type, VolumeRAIDInfo,
- PoolRAIDInfo)
+ PoolRAIDInfo, VcrCap)
## Wraps the invocation to the command line
@@ -242,6 +242,37 @@ def _get_item(l, the_id, friendly_name='item',
raise_error=True):
),
dict(
+ name='volume-create-raid',
+ help='Creates a RAIDed volume on hardware RAID',
+ args=[
+ dict(name="--name", help='volume name',
metavar='<NAME>'),
+ dict(name="--disk", metavar='<DISK>',
+ help='Free disks for new RAIDed volume.\n'
+ 'This is repeatable argument.',
+ action='append'),
+ dict(name="--raid-type",
+ help="RAID type for the new RAID group. "
+ "Should be one of these:\n %s" %
+ "\n ".join(
+ VolumeRAIDInfo.VOL_CREATE_RAID_TYPES_STR),
+ choices=VolumeRAIDInfo.VOL_CREATE_RAID_TYPES_STR,
+ type=str.upper),
+ ],
+ optional=[
+ dict(name="--strip-size",
+ help="Strip size. " + size_help),
+ ],
+ ),
+
+ dict(
+ name='volume-create-raid-cap',
+ help='Query capablity of creating a RAIDed volume on hardware RAID',
+ args=[
+ dict(sys_id_opt),
+ ],
+ ),
+
+ dict(
name='volume-delete',
help='Deletes a volume given its id',
args=[
@@ -635,6 +666,8 @@ def _get_item(l, the_id, friendly_name='item',
raise_error=True):
['c', 'capabilities'],
['p', 'plugin-info'],
['vc', 'volume-create'],
+ ['vcr', 'volume-create-raid'],
+ ['vcrc', 'volume-create-raid-cap'],
['vd', 'volume-delete'],
['vr', 'volume-resize'],
['vm', 'volume-mask'],
@@ -1351,6 +1384,38 @@ def pool_member_info(self, args):
PoolRAIDInfo(
lsm_pool.id, *self.c.pool_member_info(lsm_pool))])
+ def volume_create_raid(self, args):
+ raid_type = VolumeRAIDInfo.raid_type_str_to_lsm(args.raid_type)
+
+ all_lsm_disks = self.c.disks()
+ lsm_disks = [d for d in all_lsm_disks if d.id in args.disk]
+ if len(lsm_disks) != len(args.disk):
+ raise LsmError(
+ ErrorNumber.NOT_FOUND_DISK,
+ "Disk ID %s not found" %
+ ', '.join(set(args.disk) - set(d.id for d in all_lsm_disks)))
+
+ busy_disks = [d.id for d in lsm_disks if not d.status & Disk.STATUS_FREE]
+
+ if len(busy_disks) >= 1:
+ raise LsmError(
+ ErrorNumber.DISK_NOT_FREE,
+ "Disk %s is not free" % ", ".join(busy_disks))
+
+ if args.strip_size:
+ strip_size = size_human_2_size_bytes(args.strip_size)
+ else:
+ strip_size = Volume.VCR_STRIP_SIZE_DEFAULT
+
+ self.display_data([
+ self.c.volume_create_raid(
+ args.name, raid_type, lsm_disks, strip_size)])
+
+ def volume_create_raid_cap(self, args):
+ lsm_sys = _get_item(self.c.systems(), args.sys, "System")
+ self.display_data([
+ VcrCap(lsm_sys.id, *self.c.volume_create_raid_cap_get(lsm_sys))])
+
## Displays file system dependants
def fs_dependants(self, args):
fs = _get_item(self.c.fs(), args.fs, "File System")
diff --git a/tools/lsmcli/data_display.py b/tools/lsmcli/data_display.py
index 115f15a..b9edf68 100644
--- a/tools/lsmcli/data_display.py
+++ b/tools/lsmcli/data_display.py
@@ -265,6 +265,9 @@ class VolumeRAIDInfo(object):
Volume.RAID_TYPE_UNKNOWN: 'UNKNOWN',
}
+ VOL_CREATE_RAID_TYPES_STR = [
+ 'RAID0', 'RAID1', 'RAID5', 'RAID6',
'RAID10', 'RAID50', 'RAID60']
+
def __init__(self, vol_id, raid_type, strip_size, disk_count,
min_io_size, opt_io_size):
self.vol_id = vol_id
@@ -278,6 +281,10 @@ def __init__(self, vol_id, raid_type, strip_size, disk_count,
def raid_type_to_str(raid_type):
return _enum_type_to_str(raid_type, VolumeRAIDInfo._RAID_TYPE_MAP)
+ @staticmethod
+ def raid_type_str_to_lsm(raid_type_str):
+ return _str_to_enum(raid_type_str, VolumeRAIDInfo._RAID_TYPE_MAP)
+
class PoolRAIDInfo(object):
_MEMBER_TYPE_MAP = {
@@ -298,6 +305,11 @@ def member_type_to_str(member_type):
return _enum_type_to_str(
member_type, PoolRAIDInfo._MEMBER_TYPE_MAP)
+class VcrCap(object):
+ def __init__(self, system_id, raid_types, strip_sizes):
+ self.system_id = system_id
+ self.raid_types = raid_types
+ self.strip_sizes = strip_sizes
class DisplayData(object):
@@ -598,6 +610,25 @@ def __init__(self):
'value_conv_human': POOL_RAID_INFO_VALUE_CONV_HUMAN,
}
+ VCR_CAP_HEADER = OrderedDict()
+ VCR_CAP_HEADER['system_id'] = 'System ID'
+ VCR_CAP_HEADER['raid_types'] = 'Supported RAID Types'
+ VCR_CAP_HEADER['strip_sizes'] = 'Supported Strip Sizes'
+
+ VCR_CAP_COLUMN_SKIP_KEYS = []
+
+ VCR_CAP_VALUE_CONV_ENUM = {
+ 'raid_types': lambda i: [VolumeRAIDInfo.raid_type_to_str(x) for x in i]
+ }
+ VCR_CAP_VALUE_CONV_HUMAN = ['strip_sizes']
+
+ VALUE_CONVERT[VcrCap] = {
+ 'headers': VCR_CAP_HEADER,
+ 'column_skip_keys': VCR_CAP_COLUMN_SKIP_KEYS,
+ 'value_conv_enum': VCR_CAP_VALUE_CONV_ENUM,
+ 'value_conv_human': VCR_CAP_VALUE_CONV_HUMAN,
+ }
+
@staticmethod
def _get_man_pro_value(obj, key, value_conv_enum, value_conv_human,
flag_human, flag_enum):
@@ -607,7 +638,10 @@ def _get_man_pro_value(obj, key, value_conv_enum, value_conv_human,
value = value_conv_enum[key](value)
if flag_human:
if key in value_conv_human:
- value = size_bytes_2_size_human(value)
+ if type(value) is list:
+ value = list(size_bytes_2_size_human(s) for s in value)
+ else:
+ value = size_bytes_2_size_human(value)
return value
@staticmethod
--
1.8.3.1