Merge "Huawei driver support storage pools"
This commit is contained in:
commit
51a2bbefe1
@ -59,5 +59,9 @@ class HuaweiBase(object):
|
||||
def get_network_allocations_number(self):
|
||||
"""Get number of network interfaces to be created."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_pool(self, share):
|
||||
"""Return pool name where the share resides on."""
|
||||
|
||||
def update_share_stats(self, stats_dict):
|
||||
"""Retrieve stats info from share group."""
|
||||
|
@ -139,6 +139,11 @@ class HuaweiNasDriver(driver.ShareDriver):
|
||||
|
||||
self.plugin.deny_access(share, access, share_server)
|
||||
|
||||
def get_pool(self, share):
|
||||
"""Return pool name where the share resides on."""
|
||||
LOG.debug("Get pool.")
|
||||
return self.plugin.get_pool(share)
|
||||
|
||||
def get_network_allocations_number(self):
|
||||
"""Get number of network interfaces to be created."""
|
||||
LOG.debug("Get network allocations number.")
|
||||
@ -151,7 +156,9 @@ class HuaweiNasDriver(driver.ShareDriver):
|
||||
data = dict(
|
||||
share_backend_name=backend_name or 'HUAWEI_NAS_Driver',
|
||||
vendor_name='Huawei',
|
||||
storage_protocol='NFS_CIFS')
|
||||
storage_protocol='NFS_CIFS',
|
||||
total_capacity_gb=0.0,
|
||||
free_capacity_gb=0.0)
|
||||
|
||||
self.plugin.update_share_stats(data)
|
||||
super(HuaweiNasDriver, self)._update_share_stats(data)
|
||||
|
@ -24,6 +24,7 @@ from manila.i18n import _, _LI, _LW
|
||||
from manila.share.drivers.huawei import base as driver
|
||||
from manila.share.drivers.huawei import constants
|
||||
from manila.share.drivers.huawei.v3 import helper
|
||||
from manila.share import utils as share_utils
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
@ -47,13 +48,25 @@ class V3StorageConnection(driver.HuaweiBase):
|
||||
share_name = share['name']
|
||||
share_proto = share['share_proto']
|
||||
|
||||
pool_name = share_utils.extract_host(share['host'], level='pool')
|
||||
|
||||
if not pool_name:
|
||||
msg = _("Pool is not available in the share host field.")
|
||||
raise exception.InvalidHost(reason=msg)
|
||||
|
||||
result = self.helper._find_all_pool_info()
|
||||
poolinfo = self.helper._find_pool_info(pool_name, result)
|
||||
if not poolinfo:
|
||||
msg = (_("Can not find pool info by pool name: %s") % pool_name)
|
||||
raise exception.InvalidHost(reason=msg)
|
||||
|
||||
fs_id = None
|
||||
# We sleep here to ensure the newly created filesystem can be read.
|
||||
wait_interval = self._get_wait_interval()
|
||||
timeout = self._get_timeout()
|
||||
|
||||
try:
|
||||
fs_id = self.allocate_container(share)
|
||||
fs_id = self.allocate_container(share, poolinfo)
|
||||
fs = self.helper._get_fs_info_by_id(fs_id)
|
||||
end_time = time.time() + timeout
|
||||
|
||||
@ -162,18 +175,30 @@ class V3StorageConnection(driver.HuaweiBase):
|
||||
|
||||
def update_share_stats(self, stats_dict):
|
||||
"""Retrieve status info from share group."""
|
||||
capacity = self._get_capacity()
|
||||
root = self.helper._read_xml()
|
||||
pool_name_list = root.findtext('Filesystem/StoragePool')
|
||||
if not pool_name_list:
|
||||
err_msg = _("The StoragePool is None.")
|
||||
LOG.error(err_msg)
|
||||
raise exception.InvalidInput(err_msg)
|
||||
|
||||
pool_name_list = pool_name_list.split(";")
|
||||
|
||||
result = self.helper._find_all_pool_info()
|
||||
stats_dict["pools"] = []
|
||||
pool = {}
|
||||
pool.update(dict(
|
||||
pool_name=capacity['name'],
|
||||
total_capacity_gb=capacity['TOTALCAPACITY'],
|
||||
free_capacity_gb=capacity['CAPACITY'],
|
||||
QoS_support=False,
|
||||
reserved_percentage=0,
|
||||
))
|
||||
stats_dict["pools"].append(pool)
|
||||
for pool_name in pool_name_list:
|
||||
pool_name = pool_name.strip().strip('\n')
|
||||
capacity = self._get_capacity(pool_name, result)
|
||||
if capacity:
|
||||
pool = dict(
|
||||
pool_name=pool_name,
|
||||
total_capacity_gb=capacity['TOTALCAPACITY'],
|
||||
free_capacity_gb=capacity['CAPACITY'],
|
||||
allocated_capacity_gb=capacity['CONSUMEDCAPACITY'],
|
||||
QoS_support=False,
|
||||
reserved_percentage=0,
|
||||
)
|
||||
stats_dict["pools"].append(pool)
|
||||
|
||||
def delete_share(self, share, share_server=None):
|
||||
"""Delete share."""
|
||||
@ -206,23 +231,24 @@ class V3StorageConnection(driver.HuaweiBase):
|
||||
"""Get number of network interfaces to be created."""
|
||||
return constants.IP_ALLOCATIONS
|
||||
|
||||
def _get_capacity(self):
|
||||
def _get_capacity(self, pool_name, result):
|
||||
"""Get free capacity and total capacity of the pools."""
|
||||
poolinfo = self.helper._find_pool_info()
|
||||
poolinfo = self.helper._find_pool_info(pool_name, result)
|
||||
|
||||
if poolinfo:
|
||||
total = int(poolinfo['TOTALCAPACITY']) / units.Mi / 2
|
||||
free = int(poolinfo['CAPACITY']) / units.Mi / 2
|
||||
consumed = int(poolinfo['CONSUMEDCAPACITY']) / units.Mi / 2
|
||||
poolinfo['TOTALCAPACITY'] = total
|
||||
poolinfo['CAPACITY'] = free
|
||||
poolinfo['CONSUMEDCAPACITY'] = consumed
|
||||
|
||||
return poolinfo
|
||||
|
||||
def _init_filesys_para(self, share):
|
||||
def _init_filesys_para(self, share, poolinfo):
|
||||
"""Init basic filesystem parameters."""
|
||||
name = share['name']
|
||||
size = share['size'] * units.Mi * 2
|
||||
poolinfo = self.helper._find_pool_info()
|
||||
fileparam = {
|
||||
"NAME": name.replace("-", "_"),
|
||||
"DESCRIPTION": "",
|
||||
@ -335,9 +361,24 @@ class V3StorageConnection(driver.HuaweiBase):
|
||||
self.helper._allow_access_rest(share_id, access_to,
|
||||
share_proto, access_level)
|
||||
|
||||
def allocate_container(self, share):
|
||||
def get_pool(self, share):
|
||||
pool_name = share_utils.extract_host(share['host'], level='pool')
|
||||
if pool_name:
|
||||
return pool_name
|
||||
share_name = share['name']
|
||||
share_url_type = self.helper._get_share_url_type(share['share_proto'])
|
||||
share = self.helper._get_share_by_name(share_name, share_url_type)
|
||||
|
||||
pool_name = None
|
||||
if share:
|
||||
pool = self.helper._get_fs_info_by_id(share['FSID'])
|
||||
pool_name = pool['POOLNAME']
|
||||
|
||||
return pool_name
|
||||
|
||||
def allocate_container(self, share, poolinfo):
|
||||
"""Creates filesystem associated to share by name."""
|
||||
fileParam = self._init_filesys_para(share)
|
||||
fileParam = self._init_filesys_para(share, poolinfo)
|
||||
fsid = self.helper._create_filesystem(fileParam)
|
||||
return fsid
|
||||
|
||||
|
@ -323,30 +323,33 @@ class RestHelper(object):
|
||||
|
||||
self._assert_rest_result(result, 'Start CIFS service error.')
|
||||
|
||||
def _find_pool_info(self):
|
||||
root = self._read_xml()
|
||||
pool_name = root.findtext('Filesystem/StoragePool')
|
||||
if not pool_name:
|
||||
err_msg = (_("Invalid resource pool: %s.") % pool_name)
|
||||
LOG.error(err_msg)
|
||||
raise exception.InvalidInput(err_msg)
|
||||
|
||||
url = self.url + "/storagepool"
|
||||
result = self.call(url, None)
|
||||
self._assert_rest_result(result, 'Query resource pool error.')
|
||||
def _find_pool_info(self, pool_name, result):
|
||||
if pool_name is None:
|
||||
return
|
||||
|
||||
poolinfo = {}
|
||||
pool_name = pool_name.strip()
|
||||
for item in result.get('data', []):
|
||||
if pool_name == item['NAME']:
|
||||
if pool_name == item['NAME'] and '2' == item['USAGETYPE']:
|
||||
poolinfo['name'] = pool_name
|
||||
poolinfo['ID'] = item['ID']
|
||||
poolinfo['CAPACITY'] = item['USERFREECAPACITY']
|
||||
poolinfo['TOTALCAPACITY'] = item['USERTOTALCAPACITY']
|
||||
poolinfo['CONSUMEDCAPACITY'] = item['USERCONSUMEDCAPACITY']
|
||||
break
|
||||
|
||||
return poolinfo
|
||||
|
||||
def _find_all_pool_info(self):
|
||||
url = self.url + "/storagepool"
|
||||
result = self.call(url, None)
|
||||
|
||||
msg = "Query resource pool error."
|
||||
self._assert_rest_result(result, msg)
|
||||
self._assert_data_in_result(result, msg)
|
||||
|
||||
return result
|
||||
|
||||
def _read_xml(self):
|
||||
"""Open xml file and parse the content."""
|
||||
filename = self.configuration.manila_huawei_conf_file
|
||||
@ -580,6 +583,7 @@ class RestHelper(object):
|
||||
fs = {}
|
||||
fs['HEALTHSTATUS'] = result['data']['HEALTHSTATUS']
|
||||
fs['RUNNINGSTATUS'] = result['data']['RUNNINGSTATUS']
|
||||
fs['POOLNAME'] = result['data']['PARENTNAME']
|
||||
return fs
|
||||
|
||||
def _get_share_path(self, share_name):
|
||||
|
@ -64,11 +64,13 @@ def filesystem(method, data, fs_status_flag):
|
||||
if fs_status_flag:
|
||||
data = """{"error":{"code":0},
|
||||
"data":{"HEALTHSTATUS":"1",
|
||||
"RUNNINGSTATUS":"27"}}"""
|
||||
"RUNNINGSTATUS":"27",
|
||||
"PARENTNAME":"OpenStack_Pool"}}"""
|
||||
else:
|
||||
data = """{"error":{"code":0},
|
||||
"data":{"HEALTHSTATUS":"0",
|
||||
"RUNNINGSTATUS":"27"}}"""
|
||||
"RUNNINGSTATUS":"27",
|
||||
"PARENTNAME":"OpenStack_Pool"}}"""
|
||||
else:
|
||||
data = '{"error":{"code":31755596}}'
|
||||
return (data, extend_share_flag)
|
||||
@ -171,7 +173,9 @@ class FakeHuaweiNasHelper(helper.RestHelper):
|
||||
"data":[{"USERFREECAPACITY":"2097152",
|
||||
"ID":"1",
|
||||
"NAME":"OpenStack_Pool",
|
||||
"USERTOTALCAPACITY":"4194304"}]}"""
|
||||
"USERTOTALCAPACITY":"4194304",
|
||||
"USAGETYPE":"2",
|
||||
"USERCONSUMEDCAPACITY":"2097152"}]}"""
|
||||
|
||||
if url == "filesystem":
|
||||
data = """{"error":{"code":0},"data":{
|
||||
@ -196,7 +200,7 @@ class FakeHuaweiNasHelper(helper.RestHelper):
|
||||
else:
|
||||
data = """{"error":{"code":0},
|
||||
"data":[{"ID":"1",
|
||||
"FSID":"4",
|
||||
"FSID":"",
|
||||
"NAME":"test",
|
||||
"SHAREPATH":"/share_fake_uuid_fail/"}]}"""
|
||||
|
||||
@ -393,6 +397,7 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||
'share_proto': 'NFS',
|
||||
'share_network_id': 'fake_net_id',
|
||||
'share_server_id': 'fake-share-srv-id',
|
||||
'host': 'fake_host@fake_backend#OpenStack_Pool',
|
||||
}
|
||||
|
||||
self.share_proto_fail = {
|
||||
@ -404,6 +409,7 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||
'share_proto': 'proto_fail',
|
||||
'share_network_id': 'fake_net_id',
|
||||
'share_server_id': 'fake-share-srv-id',
|
||||
'host': 'fake_host@fake_backend#OpenStack_Pool',
|
||||
}
|
||||
|
||||
self.share_cifs = {
|
||||
@ -415,6 +421,7 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||
'share_proto': 'CIFS',
|
||||
'share_network_id': 'fake_net_id',
|
||||
'share_server_id': 'fake-share-srv-id',
|
||||
'host': 'fake_host@fake_backend#OpenStack_Pool',
|
||||
}
|
||||
|
||||
self.nfs_snapshot = {
|
||||
@ -473,6 +480,30 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||
],
|
||||
}
|
||||
|
||||
self.share_nfs_host_not_exist = {
|
||||
'id': 'fake_uuid',
|
||||
'project_id': 'fake_tenant_id',
|
||||
'display_name': 'fake',
|
||||
'name': 'share-fake-uuid',
|
||||
'size': 1,
|
||||
'share_proto': 'NFS',
|
||||
'share_network_id': 'fake_net_id',
|
||||
'share_server_id': 'fake-share-srv-id',
|
||||
'host': 'fake_host@fake_backend#',
|
||||
}
|
||||
|
||||
self.share_nfs_storagepool_fail = {
|
||||
'id': 'fake_uuid',
|
||||
'project_id': 'fake_tenant_id',
|
||||
'display_name': 'fake',
|
||||
'name': 'share-fake-uuid',
|
||||
'size': 1,
|
||||
'share_proto': 'NFS',
|
||||
'share_network_id': 'fake_net_id',
|
||||
'share_server_id': 'fake-share-srv-id',
|
||||
'host': 'fake_host@fake_backend#OpenStack_Pool2',
|
||||
}
|
||||
|
||||
def test_conf_product_fail(self):
|
||||
self.recreate_fake_conf_file(product_flag=False)
|
||||
self.driver.plugin.configuration.manila_huawei_conf_file = (
|
||||
@ -533,15 +564,20 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||
self.share_nfs,
|
||||
self.share_server)
|
||||
|
||||
def test_create_share_nfs_storagepool_fail(self):
|
||||
self.recreate_fake_conf_file(pool_node_flag=False)
|
||||
self.driver.plugin.configuration.manila_huawei_conf_file = (
|
||||
self.fake_conf_file)
|
||||
def test_create_share_storagepool_not_exist(self):
|
||||
self.driver.plugin.helper.login()
|
||||
self.assertRaises(exception.InvalidShare,
|
||||
self.assertRaises(exception.InvalidHost,
|
||||
self.driver.create_share,
|
||||
self._context,
|
||||
self.share_nfs,
|
||||
self.share_nfs_host_not_exist,
|
||||
self.share_server)
|
||||
|
||||
def test_create_share_nfs_storagepool_fail(self):
|
||||
self.driver.plugin.helper.login()
|
||||
self.assertRaises(exception.InvalidHost,
|
||||
self.driver.create_share,
|
||||
self._context,
|
||||
self.share_nfs_storagepool_fail,
|
||||
self.share_server)
|
||||
|
||||
def test_create_share_nfs_no_data_fail(self):
|
||||
@ -725,6 +761,14 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||
self._context, self.share_nfs, self.nfs_snapshot,
|
||||
self.share_server)
|
||||
|
||||
def test_get_share_stats_refresh_pool_not_exist(self):
|
||||
self.driver.plugin.helper.login()
|
||||
self.recreate_fake_conf_file(pool_node_flag=False)
|
||||
self.driver.plugin.configuration.manila_huawei_conf_file = (
|
||||
self.fake_conf_file)
|
||||
self.assertRaises(exception.InvalidInput,
|
||||
self.driver._update_share_stats)
|
||||
|
||||
def test_get_share_stats_refresh(self):
|
||||
self.driver.plugin.helper.login()
|
||||
self.driver._update_share_stats()
|
||||
@ -736,8 +780,8 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||
expected["driver_version"] = '1.0'
|
||||
expected["storage_protocol"] = 'NFS_CIFS'
|
||||
expected['reserved_percentage'] = 0
|
||||
expected['total_capacity_gb'] = 'infinite'
|
||||
expected['free_capacity_gb'] = 'infinite'
|
||||
expected['total_capacity_gb'] = 0.0
|
||||
expected['free_capacity_gb'] = 0.0
|
||||
expected['QoS_support'] = False
|
||||
expected["pools"] = []
|
||||
pool = {}
|
||||
@ -745,19 +789,14 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||
pool_name='OpenStack_Pool',
|
||||
total_capacity_gb=2,
|
||||
free_capacity_gb=1,
|
||||
allocated_capacity_gb=1,
|
||||
QoS_support=False,
|
||||
reserved_percentage=0,
|
||||
))
|
||||
|
||||
expected["pools"].append(pool)
|
||||
self.assertEqual(expected, self.driver._stats)
|
||||
|
||||
def test_get_capacity_success(self):
|
||||
self.driver.plugin.helper.login()
|
||||
capacity = {}
|
||||
capacity = self.driver.plugin._get_capacity()
|
||||
self.assertEqual(2, capacity['TOTALCAPACITY'])
|
||||
self.assertEqual(1, capacity['CAPACITY'])
|
||||
|
||||
def test_allow_access_proto_fail(self):
|
||||
self.driver.plugin.helper.login()
|
||||
self.assertRaises(exception.InvalidInput,
|
||||
@ -995,6 +1034,17 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||
self.driver.delete_snapshot, self._context,
|
||||
self.cifs_snapshot, self.share_server)
|
||||
|
||||
def test_get_pool_success(self):
|
||||
self.driver.plugin.helper.login()
|
||||
pool_name = self.driver.get_pool(self.share_nfs_host_not_exist)
|
||||
self.assertEqual('OpenStack_Pool', pool_name)
|
||||
|
||||
def test_get_pool_fail(self):
|
||||
self.driver.plugin.helper.login()
|
||||
self.driver.plugin.helper.share_exist = False
|
||||
pool_name = self.driver.get_pool(self.share_nfs_host_not_exist)
|
||||
self.assertEqual(None, pool_name)
|
||||
|
||||
def test_multi_resturls_success(self):
|
||||
self.recreate_fake_conf_file(multi_url=True)
|
||||
self.driver.plugin.configuration.manila_huawei_conf_file = (
|
||||
@ -1074,7 +1124,7 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||
|
||||
storagepool = doc.createElement('StoragePool')
|
||||
if pool_node_flag:
|
||||
pool_text = doc.createTextNode('OpenStack_Pool')
|
||||
pool_text = doc.createTextNode('OpenStack_Pool;OpenStack_Pool2; ;')
|
||||
else:
|
||||
pool_text = doc.createTextNode('')
|
||||
storagepool.appendChild(pool_text)
|
||||
|
Loading…
Reference in New Issue
Block a user