* Add support of these methods:
* volume_create_raid()
* volume_create_raid_cap_get()
* Using storcli command to create RAID group volume:
storcli /c0 add vd RAID10 drives=252:1-4 pdperarray=2 J
* Fixed incorrect lsm.System.plugin_data.
* Add new capability lsm.Capabilities.VOLUME_CREATE_RAID.
Signed-off-by: Gris Ge <fge(a)redhat.com>
---
plugin/megaraid/megaraid.py | 194 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 193 insertions(+), 1 deletion(-)
diff --git a/plugin/megaraid/megaraid.py b/plugin/megaraid/megaraid.py
index 46e7916..990548b 100644
--- a/plugin/megaraid/megaraid.py
+++ b/plugin/megaraid/megaraid.py
@@ -19,6 +19,7 @@
import json
import re
import errno
+import math
from lsm import (uri_parse, search_property, size_human_2_size_bytes,
Capabilities, LsmError, ErrorNumber, System, Client,
@@ -188,6 +189,27 @@ def _mega_raid_type_to_lsm(vd_basic_info, vd_prop_info):
return raid_type
+def _lsm_raid_type_to_mega(lsm_raid_type):
+ if lsm_raid_type == Volume.RAID_TYPE_RAID0:
+ return 'RAID0'
+ elif lsm_raid_type == Volume.RAID_TYPE_RAID1:
+ return 'RAID1'
+ elif lsm_raid_type == Volume.RAID_TYPE_RAID5:
+ return 'RAID5'
+ elif lsm_raid_type == Volume.RAID_TYPE_RAID6:
+ return 'RAID6'
+ elif lsm_raid_type == Volume.RAID_TYPE_RAID10:
+ return 'RAID10'
+ elif lsm_raid_type == Volume.RAID_TYPE_RAID50:
+ return 'RAID50'
+ elif lsm_raid_type == Volume.RAID_TYPE_RAID60:
+ return 'RAID60'
+ else:
+ raise LsmError(
+ ErrorNumber.NO_SUPPORT,
+ "RAID type %d not supported" % lsm_raid_type)
+
+
class MegaRAID(IPlugin):
_DEFAULT_BIN_PATHS = [
"/opt/MegaRAID/storcli/storcli64",
"/opt/MegaRAID/storcli/storcli"]
@@ -261,6 +283,7 @@ def capabilities(self, system, flags=Client.FLAG_RSVD):
cap.set(Capabilities.VOLUMES)
cap.set(Capabilities.VOLUME_RAID_INFO)
cap.set(Capabilities.POOL_MEMBER_INFO)
+ cap.set(Capabilities.VOLUME_CREATE_RAID)
return cap
def _storcli_exec(self, storcli_cmds, flag_json=True):
@@ -347,7 +370,7 @@ def systems(self, flags=Client.FLAG_RSVD):
)
(status, status_info) = self._lsm_status_of_ctrl(
ctrl_show_all_output)
- plugin_data = "/c%d"
+ plugin_data = "/c%d" % ctrl_num
# Since PCI slot sequence might change.
# This string just stored for quick system verification.
@@ -601,3 +624,172 @@ def pool_member_info(self, pool, flags=Client.FLAG_RSVD):
raid_type = Volume.RAID_TYPE_RAID10
return raid_type, Pool.MEMBER_TYPE_DISK, disk_ids
+
+ def _vcr_cap_get(self, mega_sys_path):
+ cap_output = self._storcli_exec(
+ [mega_sys_path, "show", "all"])['Capabilities']
+
+ mega_raid_types = \
+ cap_output['RAID Level Supported'].replace(', \n',
'').split(', ')
+
+ supported_raid_types = []
+ if 'RAID0' in mega_raid_types:
+ supported_raid_types.append(Volume.RAID_TYPE_RAID0)
+
+ if 'RAID1' in mega_raid_types:
+ supported_raid_types.append(Volume.RAID_TYPE_RAID1)
+
+ if 'RAID5' in mega_raid_types:
+ supported_raid_types.append(Volume.RAID_TYPE_RAID5)
+
+ if 'RAID6' in mega_raid_types:
+ supported_raid_types.append(Volume.RAID_TYPE_RAID6)
+
+ if 'RAID10' in mega_raid_types:
+ supported_raid_types.append(Volume.RAID_TYPE_RAID10)
+
+ if 'RAID50' in mega_raid_types:
+ supported_raid_types.append(Volume.RAID_TYPE_RAID50)
+
+ if 'RAID60' in mega_raid_types:
+ supported_raid_types.append(Volume.RAID_TYPE_RAID60)
+
+ min_strip_size = _mega_size_to_lsm(cap_output['Min Strip Size'])
+ max_strip_size = _mega_size_to_lsm(cap_output['Max Strip Size'])
+
+ supported_strip_sizes = list(
+ min_strip_size * (2 ** i)
+ for i in range(
+ 0,
+ int(
+ math.log(int(max_strip_size / min_strip_size)) /
+ math.log(2)) + 1))
+
+ # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ # The math above is to generate a list like:
+ # min_strip_size, ... n^2 , max_strip_size
+
+ return supported_raid_types, supported_strip_sizes
+
+ @_handle_errors
+ def volume_create_raid_cap_get(self, system, flags=Client.FLAG_RSVD):
+ """
+ Depend on the 'Capabilities' section of "storcli /c0 show all"
output.
+ """
+ cur_lsm_syss = list(s for s in self.systems() if s.id == system.id)
+ if len(cur_lsm_syss) != 1:
+ raise LsmError(
+ ErrorNumber.NOT_FOUND_SYSTEM,
+ "System not found")
+
+ lsm_sys = cur_lsm_syss[0]
+ return self._vcr_cap_get(lsm_sys.plugin_data)
+
+ @_handle_errors
+ def volume_create_raid(self, name, raid_type, disks, strip_size,
+ flags=Client.FLAG_RSVD):
+ """
+ Work flow:
+ 1. Create RAID volume
+ storcli /c0 add vd RAID10 drives=252:1-4 pdperarray=2 J
+ 2. Find out pool/DG base on one disk.
+ storcli /c0/e252/s1 show J
+ 3. Find out the volume/VD base on pool/DG using self.volumes()
+ """
+ mega_raid_type = _lsm_raid_type_to_mega(raid_type)
+ ctrl_num = None
+ slot_nums = []
+ enclosure_num = None
+
+ for disk in disks:
+ if not disk.plugin_data:
+ raise LsmError(
+ ErrorNumber.INVALID_ARGUMENT,
+ "Illegal input disks argument: missing plugin_data "
+ "property")
+ # Disk should from the same controller.
+ (cur_ctrl_num, cur_enclosure_num, slot_num) = \
+ disk.plugin_data.split(':')
+
+ if ctrl_num and cur_ctrl_num != ctrl_num:
+ raise LsmError(
+ ErrorNumber.INVALID_ARGUMENT,
+ "Illegal input disks argument: disks are not from the "
+ "same controller/system.")
+
+ if enclosure_num and cur_enclosure_num != enclosure_num:
+ raise LsmError(
+ ErrorNumber.INVALID_ARGUMENT,
+ "Illegal input disks argument: disks are not from the "
+ "same disk enclosure.")
+
+ ctrl_num = int(cur_ctrl_num)
+ enclosure_num = cur_enclosure_num
+ slot_nums.append(slot_num)
+
+ # Handle request volume name, LSI only allow 15 characters.
+ name = re.sub('[^0-9a-zA-Z_\-]+', '', name)[:15]
+
+ cmds = [
+ "/c%s" % ctrl_num, "add", "vd",
mega_raid_type,
+ 'size=all', "name=%s" % name,
+ "drives=%s:%s" % (enclosure_num, ','.join(slot_nums))]
+
+ if raid_type == Volume.RAID_TYPE_RAID10 or \
+ raid_type == Volume.RAID_TYPE_RAID50 or \
+ raid_type == Volume.RAID_TYPE_RAID60:
+ cmds.append("pdperarray=%d" % int(len(disks) / 2))
+
+ if strip_size != Volume.VCR_STRIP_SIZE_DEFAULT:
+ cmds.append("strip=%d" % int(strip_size / 1024))
+
+ try:
+ self._storcli_exec(cmds)
+ except ExecError:
+ req_disk_ids = [d.id for d in disks]
+ for cur_disk in self.disks():
+ if cur_disk.id in req_disk_ids and \
+ not cur_disk.status & Disk.STATUS_FREE:
+ raise LsmError(
+ ErrorNumber.DISK_NOT_FREE,
+ "Disk %s is not in STATUS_FREE state" % cur_disk.id)
+ # Check whether got unsupported RAID type or stripe size
+ supported_raid_types, supported_strip_sizes = \
+ self._vcr_cap_get("/c%s" % ctrl_num)
+
+ if raid_type not in supported_raid_types:
+ raise LsmError(
+ ErrorNumber.NO_SUPPORT,
+ "Provided 'raid_type' is not supported")
+
+ if strip_size != Volume.VCR_STRIP_SIZE_DEFAULT and \
+ strip_size not in supported_strip_sizes:
+ raise LsmError(
+ ErrorNumber.NO_SUPPORT,
+ "Provided 'strip_size' is not supported")
+
+ raise
+
+ # Find out the DG ID from one disk.
+ dg_show_output = self._storcli_exec(
+ ["/c%s/e%s/s%s" % tuple(disks[0].plugin_data.split(":")),
"show"])
+
+ dg_id = dg_show_output['Drive Information'][0]['DG']
+ if dg_id == '-':
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "volume_create_raid(): No error found in output, "
+ "but RAID is not created: %s" % dg_show_output.items())
+ else:
+ dg_id = int(dg_id)
+
+ pool_id = _pool_id_of(dg_id, self._sys_id_of_ctrl_num(ctrl_num))
+
+ lsm_vols = self.volumes(search_key='pool_id', search_value=pool_id)
+ if len(lsm_vols) != 1:
+ raise LsmError(
+ ErrorNumber.PLUGIN_BUG,
+ "volume_create_raid(): Got unexpected volume count(not 1) "
+ "when creating RAID volume")
+
+ return lsm_vols[0]
--
1.8.3.1