Merge "Huawei driver support storage pools"

This commit is contained in:
Jenkins 2015-07-22 01:36:31 +00:00 committed by Gerrit Code Review
commit 51a2bbefe1
5 changed files with 156 additions and 50 deletions

View File

@ -59,5 +59,9 @@ class HuaweiBase(object):
def get_network_allocations_number(self): def get_network_allocations_number(self):
"""Get number of network interfaces to be created.""" """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): def update_share_stats(self, stats_dict):
"""Retrieve stats info from share group.""" """Retrieve stats info from share group."""

View File

@ -139,6 +139,11 @@ class HuaweiNasDriver(driver.ShareDriver):
self.plugin.deny_access(share, access, share_server) 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): def get_network_allocations_number(self):
"""Get number of network interfaces to be created.""" """Get number of network interfaces to be created."""
LOG.debug("Get network allocations number.") LOG.debug("Get network allocations number.")
@ -151,7 +156,9 @@ class HuaweiNasDriver(driver.ShareDriver):
data = dict( data = dict(
share_backend_name=backend_name or 'HUAWEI_NAS_Driver', share_backend_name=backend_name or 'HUAWEI_NAS_Driver',
vendor_name='Huawei', 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) self.plugin.update_share_stats(data)
super(HuaweiNasDriver, self)._update_share_stats(data) super(HuaweiNasDriver, self)._update_share_stats(data)

View File

@ -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 base as driver
from manila.share.drivers.huawei import constants from manila.share.drivers.huawei import constants
from manila.share.drivers.huawei.v3 import helper from manila.share.drivers.huawei.v3 import helper
from manila.share import utils as share_utils
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
@ -47,13 +48,25 @@ class V3StorageConnection(driver.HuaweiBase):
share_name = share['name'] share_name = share['name']
share_proto = share['share_proto'] 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 fs_id = None
# We sleep here to ensure the newly created filesystem can be read. # We sleep here to ensure the newly created filesystem can be read.
wait_interval = self._get_wait_interval() wait_interval = self._get_wait_interval()
timeout = self._get_timeout() timeout = self._get_timeout()
try: try:
fs_id = self.allocate_container(share) fs_id = self.allocate_container(share, poolinfo)
fs = self.helper._get_fs_info_by_id(fs_id) fs = self.helper._get_fs_info_by_id(fs_id)
end_time = time.time() + timeout end_time = time.time() + timeout
@ -162,18 +175,30 @@ class V3StorageConnection(driver.HuaweiBase):
def update_share_stats(self, stats_dict): def update_share_stats(self, stats_dict):
"""Retrieve status info from share group.""" """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"] = [] stats_dict["pools"] = []
pool = {} for pool_name in pool_name_list:
pool.update(dict( pool_name = pool_name.strip().strip('\n')
pool_name=capacity['name'], capacity = self._get_capacity(pool_name, result)
total_capacity_gb=capacity['TOTALCAPACITY'], if capacity:
free_capacity_gb=capacity['CAPACITY'], pool = dict(
QoS_support=False, pool_name=pool_name,
reserved_percentage=0, total_capacity_gb=capacity['TOTALCAPACITY'],
)) free_capacity_gb=capacity['CAPACITY'],
stats_dict["pools"].append(pool) allocated_capacity_gb=capacity['CONSUMEDCAPACITY'],
QoS_support=False,
reserved_percentage=0,
)
stats_dict["pools"].append(pool)
def delete_share(self, share, share_server=None): def delete_share(self, share, share_server=None):
"""Delete share.""" """Delete share."""
@ -206,23 +231,24 @@ class V3StorageConnection(driver.HuaweiBase):
"""Get number of network interfaces to be created.""" """Get number of network interfaces to be created."""
return constants.IP_ALLOCATIONS return constants.IP_ALLOCATIONS
def _get_capacity(self): def _get_capacity(self, pool_name, result):
"""Get free capacity and total capacity of the pools.""" """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: if poolinfo:
total = int(poolinfo['TOTALCAPACITY']) / units.Mi / 2 total = int(poolinfo['TOTALCAPACITY']) / units.Mi / 2
free = int(poolinfo['CAPACITY']) / units.Mi / 2 free = int(poolinfo['CAPACITY']) / units.Mi / 2
consumed = int(poolinfo['CONSUMEDCAPACITY']) / units.Mi / 2
poolinfo['TOTALCAPACITY'] = total poolinfo['TOTALCAPACITY'] = total
poolinfo['CAPACITY'] = free poolinfo['CAPACITY'] = free
poolinfo['CONSUMEDCAPACITY'] = consumed
return poolinfo return poolinfo
def _init_filesys_para(self, share): def _init_filesys_para(self, share, poolinfo):
"""Init basic filesystem parameters.""" """Init basic filesystem parameters."""
name = share['name'] name = share['name']
size = share['size'] * units.Mi * 2 size = share['size'] * units.Mi * 2
poolinfo = self.helper._find_pool_info()
fileparam = { fileparam = {
"NAME": name.replace("-", "_"), "NAME": name.replace("-", "_"),
"DESCRIPTION": "", "DESCRIPTION": "",
@ -335,9 +361,24 @@ class V3StorageConnection(driver.HuaweiBase):
self.helper._allow_access_rest(share_id, access_to, self.helper._allow_access_rest(share_id, access_to,
share_proto, access_level) 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.""" """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) fsid = self.helper._create_filesystem(fileParam)
return fsid return fsid

View File

@ -323,30 +323,33 @@ class RestHelper(object):
self._assert_rest_result(result, 'Start CIFS service error.') self._assert_rest_result(result, 'Start CIFS service error.')
def _find_pool_info(self): def _find_pool_info(self, pool_name, result):
root = self._read_xml() if pool_name is None:
pool_name = root.findtext('Filesystem/StoragePool') return
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.')
poolinfo = {} poolinfo = {}
pool_name = pool_name.strip() pool_name = pool_name.strip()
for item in result.get('data', []): 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['name'] = pool_name
poolinfo['ID'] = item['ID'] poolinfo['ID'] = item['ID']
poolinfo['CAPACITY'] = item['USERFREECAPACITY'] poolinfo['CAPACITY'] = item['USERFREECAPACITY']
poolinfo['TOTALCAPACITY'] = item['USERTOTALCAPACITY'] poolinfo['TOTALCAPACITY'] = item['USERTOTALCAPACITY']
poolinfo['CONSUMEDCAPACITY'] = item['USERCONSUMEDCAPACITY']
break break
return poolinfo 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): def _read_xml(self):
"""Open xml file and parse the content.""" """Open xml file and parse the content."""
filename = self.configuration.manila_huawei_conf_file filename = self.configuration.manila_huawei_conf_file
@ -580,6 +583,7 @@ class RestHelper(object):
fs = {} fs = {}
fs['HEALTHSTATUS'] = result['data']['HEALTHSTATUS'] fs['HEALTHSTATUS'] = result['data']['HEALTHSTATUS']
fs['RUNNINGSTATUS'] = result['data']['RUNNINGSTATUS'] fs['RUNNINGSTATUS'] = result['data']['RUNNINGSTATUS']
fs['POOLNAME'] = result['data']['PARENTNAME']
return fs return fs
def _get_share_path(self, share_name): def _get_share_path(self, share_name):

View File

@ -64,11 +64,13 @@ def filesystem(method, data, fs_status_flag):
if fs_status_flag: if fs_status_flag:
data = """{"error":{"code":0}, data = """{"error":{"code":0},
"data":{"HEALTHSTATUS":"1", "data":{"HEALTHSTATUS":"1",
"RUNNINGSTATUS":"27"}}""" "RUNNINGSTATUS":"27",
"PARENTNAME":"OpenStack_Pool"}}"""
else: else:
data = """{"error":{"code":0}, data = """{"error":{"code":0},
"data":{"HEALTHSTATUS":"0", "data":{"HEALTHSTATUS":"0",
"RUNNINGSTATUS":"27"}}""" "RUNNINGSTATUS":"27",
"PARENTNAME":"OpenStack_Pool"}}"""
else: else:
data = '{"error":{"code":31755596}}' data = '{"error":{"code":31755596}}'
return (data, extend_share_flag) return (data, extend_share_flag)
@ -171,7 +173,9 @@ class FakeHuaweiNasHelper(helper.RestHelper):
"data":[{"USERFREECAPACITY":"2097152", "data":[{"USERFREECAPACITY":"2097152",
"ID":"1", "ID":"1",
"NAME":"OpenStack_Pool", "NAME":"OpenStack_Pool",
"USERTOTALCAPACITY":"4194304"}]}""" "USERTOTALCAPACITY":"4194304",
"USAGETYPE":"2",
"USERCONSUMEDCAPACITY":"2097152"}]}"""
if url == "filesystem": if url == "filesystem":
data = """{"error":{"code":0},"data":{ data = """{"error":{"code":0},"data":{
@ -196,7 +200,7 @@ class FakeHuaweiNasHelper(helper.RestHelper):
else: else:
data = """{"error":{"code":0}, data = """{"error":{"code":0},
"data":[{"ID":"1", "data":[{"ID":"1",
"FSID":"4", "FSID":"",
"NAME":"test", "NAME":"test",
"SHAREPATH":"/share_fake_uuid_fail/"}]}""" "SHAREPATH":"/share_fake_uuid_fail/"}]}"""
@ -393,6 +397,7 @@ class HuaweiShareDriverTestCase(test.TestCase):
'share_proto': 'NFS', 'share_proto': 'NFS',
'share_network_id': 'fake_net_id', 'share_network_id': 'fake_net_id',
'share_server_id': 'fake-share-srv-id', 'share_server_id': 'fake-share-srv-id',
'host': 'fake_host@fake_backend#OpenStack_Pool',
} }
self.share_proto_fail = { self.share_proto_fail = {
@ -404,6 +409,7 @@ class HuaweiShareDriverTestCase(test.TestCase):
'share_proto': 'proto_fail', 'share_proto': 'proto_fail',
'share_network_id': 'fake_net_id', 'share_network_id': 'fake_net_id',
'share_server_id': 'fake-share-srv-id', 'share_server_id': 'fake-share-srv-id',
'host': 'fake_host@fake_backend#OpenStack_Pool',
} }
self.share_cifs = { self.share_cifs = {
@ -415,6 +421,7 @@ class HuaweiShareDriverTestCase(test.TestCase):
'share_proto': 'CIFS', 'share_proto': 'CIFS',
'share_network_id': 'fake_net_id', 'share_network_id': 'fake_net_id',
'share_server_id': 'fake-share-srv-id', 'share_server_id': 'fake-share-srv-id',
'host': 'fake_host@fake_backend#OpenStack_Pool',
} }
self.nfs_snapshot = { 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): def test_conf_product_fail(self):
self.recreate_fake_conf_file(product_flag=False) self.recreate_fake_conf_file(product_flag=False)
self.driver.plugin.configuration.manila_huawei_conf_file = ( self.driver.plugin.configuration.manila_huawei_conf_file = (
@ -533,15 +564,20 @@ class HuaweiShareDriverTestCase(test.TestCase):
self.share_nfs, self.share_nfs,
self.share_server) self.share_server)
def test_create_share_nfs_storagepool_fail(self): def test_create_share_storagepool_not_exist(self):
self.recreate_fake_conf_file(pool_node_flag=False)
self.driver.plugin.configuration.manila_huawei_conf_file = (
self.fake_conf_file)
self.driver.plugin.helper.login() self.driver.plugin.helper.login()
self.assertRaises(exception.InvalidShare, self.assertRaises(exception.InvalidHost,
self.driver.create_share, self.driver.create_share,
self._context, 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) self.share_server)
def test_create_share_nfs_no_data_fail(self): 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._context, self.share_nfs, self.nfs_snapshot,
self.share_server) 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): def test_get_share_stats_refresh(self):
self.driver.plugin.helper.login() self.driver.plugin.helper.login()
self.driver._update_share_stats() self.driver._update_share_stats()
@ -736,8 +780,8 @@ class HuaweiShareDriverTestCase(test.TestCase):
expected["driver_version"] = '1.0' expected["driver_version"] = '1.0'
expected["storage_protocol"] = 'NFS_CIFS' expected["storage_protocol"] = 'NFS_CIFS'
expected['reserved_percentage'] = 0 expected['reserved_percentage'] = 0
expected['total_capacity_gb'] = 'infinite' expected['total_capacity_gb'] = 0.0
expected['free_capacity_gb'] = 'infinite' expected['free_capacity_gb'] = 0.0
expected['QoS_support'] = False expected['QoS_support'] = False
expected["pools"] = [] expected["pools"] = []
pool = {} pool = {}
@ -745,19 +789,14 @@ class HuaweiShareDriverTestCase(test.TestCase):
pool_name='OpenStack_Pool', pool_name='OpenStack_Pool',
total_capacity_gb=2, total_capacity_gb=2,
free_capacity_gb=1, free_capacity_gb=1,
allocated_capacity_gb=1,
QoS_support=False, QoS_support=False,
reserved_percentage=0, reserved_percentage=0,
)) ))
expected["pools"].append(pool) expected["pools"].append(pool)
self.assertEqual(expected, self.driver._stats) 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): def test_allow_access_proto_fail(self):
self.driver.plugin.helper.login() self.driver.plugin.helper.login()
self.assertRaises(exception.InvalidInput, self.assertRaises(exception.InvalidInput,
@ -995,6 +1034,17 @@ class HuaweiShareDriverTestCase(test.TestCase):
self.driver.delete_snapshot, self._context, self.driver.delete_snapshot, self._context,
self.cifs_snapshot, self.share_server) 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): def test_multi_resturls_success(self):
self.recreate_fake_conf_file(multi_url=True) self.recreate_fake_conf_file(multi_url=True)
self.driver.plugin.configuration.manila_huawei_conf_file = ( self.driver.plugin.configuration.manila_huawei_conf_file = (
@ -1074,7 +1124,7 @@ class HuaweiShareDriverTestCase(test.TestCase):
storagepool = doc.createElement('StoragePool') storagepool = doc.createElement('StoragePool')
if pool_node_flag: if pool_node_flag:
pool_text = doc.createTextNode('OpenStack_Pool') pool_text = doc.createTextNode('OpenStack_Pool;OpenStack_Pool2; ;')
else: else:
pool_text = doc.createTextNode('') pool_text = doc.createTextNode('')
storagepool.appendChild(pool_text) storagepool.appendChild(pool_text)