Huawei driver report pool capabilities [True, False]
In liberty, huawei driver has been changed to support only thin or thick filesystem in one storagepool because of bug#1491272. Now in mitaka, after blueprint support-lists-in-capabilities-filter has been merged. The scheduler is able to handle one storage pool report "thin_provisioning" :[True, False]. Most of the code is the revert of bug#1491272. Change-Id: Ibde3053be02274956e9a689845d5f3ef6c005c51 Closes-Bug: #1532651
This commit is contained in:
parent
f178426266
commit
9096fc7919
|
@ -32,11 +32,14 @@ ERROR_CONNECT_TO_SERVER = -403
|
||||||
ERROR_UNAUTHORIZED_TO_SERVER = -401
|
ERROR_UNAUTHORIZED_TO_SERVER = -401
|
||||||
|
|
||||||
ALLOC_TYPE_THIN_FLAG = "1"
|
ALLOC_TYPE_THIN_FLAG = "1"
|
||||||
|
ALLOC_TYPE_THICK_FLAG = "0"
|
||||||
|
|
||||||
ALLOC_TYPE_THIN = "Thin"
|
ALLOC_TYPE_THIN = "Thin"
|
||||||
ALLOC_TYPE_THICK = "Thick"
|
ALLOC_TYPE_THICK = "Thick"
|
||||||
THIN_PROVISIONING = "true"
|
THIN_PROVISIONING = "true"
|
||||||
THICK_PROVISIONING = "false"
|
THICK_PROVISIONING = "false"
|
||||||
|
|
||||||
|
|
||||||
OPTS_CAPABILITIES = {
|
OPTS_CAPABILITIES = {
|
||||||
'dedupe': False,
|
'dedupe': False,
|
||||||
'compression': False,
|
'compression': False,
|
||||||
|
|
|
@ -236,38 +236,36 @@ class V3StorageConnection(driver.HuaweiBase):
|
||||||
all_pool_info = self.helper._find_all_pool_info()
|
all_pool_info = self.helper._find_all_pool_info()
|
||||||
stats_dict["pools"] = []
|
stats_dict["pools"] = []
|
||||||
|
|
||||||
for pool_type in ('Thin', 'Thick'):
|
pool_name_list = root.findtext('Filesystem/StoragePool')
|
||||||
pool_name_list = root.findtext(('Filesystem/%s_StoragePool'
|
pool_name_list = pool_name_list.split(";")
|
||||||
% pool_type))
|
for pool_name in pool_name_list:
|
||||||
pool_name_list = pool_name_list.split(";")
|
pool_name = pool_name.strip().strip('\n')
|
||||||
for pool_name in pool_name_list:
|
capacity = self._get_capacity(pool_name, all_pool_info)
|
||||||
pool_name = pool_name.strip().strip('\n')
|
if capacity:
|
||||||
capacity = self._get_capacity(pool_name, all_pool_info)
|
pool = dict(
|
||||||
if capacity:
|
pool_name=pool_name,
|
||||||
pool = dict(
|
total_capacity_gb=capacity['TOTALCAPACITY'],
|
||||||
pool_name=pool_name,
|
free_capacity_gb=capacity['CAPACITY'],
|
||||||
total_capacity_gb=capacity['TOTALCAPACITY'],
|
provisioned_capacity_gb=(
|
||||||
free_capacity_gb=capacity['CAPACITY'],
|
capacity['PROVISIONEDCAPACITYGB']),
|
||||||
provisioned_capacity_gb=(
|
max_over_subscription_ratio=(
|
||||||
capacity['PROVISIONEDCAPACITYGB']),
|
self.configuration.safe_get(
|
||||||
max_over_subscription_ratio=(
|
'max_over_subscription_ratio')),
|
||||||
self.configuration.safe_get(
|
allocated_capacity_gb=capacity['CONSUMEDCAPACITY'],
|
||||||
'max_over_subscription_ratio')),
|
QoS_support=False,
|
||||||
allocated_capacity_gb=capacity['CONSUMEDCAPACITY'],
|
reserved_percentage=0,
|
||||||
QoS_support=False,
|
thin_provisioning=[True, False],
|
||||||
reserved_percentage=0,
|
dedupe=[True, False],
|
||||||
thin_provisioning=(pool_type == 'Thin'),
|
compression=[True, False],
|
||||||
dedupe=(pool_type == 'Thin'),
|
huawei_smartcache=[True, False],
|
||||||
compression=(pool_type == 'Thin'),
|
huawei_smartpartition=[True, False],
|
||||||
huawei_smartcache=True,
|
)
|
||||||
huawei_smartpartition=True,
|
stats_dict["pools"].append(pool)
|
||||||
)
|
|
||||||
stats_dict["pools"].append(pool)
|
|
||||||
|
|
||||||
if not stats_dict["pools"]:
|
if not stats_dict["pools"]:
|
||||||
err_msg = _("The StoragePool is None.")
|
err_msg = _("The StoragePool is None.")
|
||||||
LOG.error(err_msg)
|
LOG.error(err_msg)
|
||||||
raise exception.InvalidInput(err_msg)
|
raise exception.InvalidInput(reason=err_msg)
|
||||||
|
|
||||||
def delete_share(self, share, share_server=None):
|
def delete_share(self, share, share_server=None):
|
||||||
"""Delete share."""
|
"""Delete share."""
|
||||||
|
@ -323,8 +321,7 @@ class V3StorageConnection(driver.HuaweiBase):
|
||||||
fileparam = {
|
fileparam = {
|
||||||
"NAME": name.replace("-", "_"),
|
"NAME": name.replace("-", "_"),
|
||||||
"DESCRIPTION": "",
|
"DESCRIPTION": "",
|
||||||
"ALLOCTYPE": (1 if poolinfo['type'] == 'Thin'
|
"ALLOCTYPE": constants.ALLOC_TYPE_THIN_FLAG,
|
||||||
else 0),
|
|
||||||
"CAPACITY": size,
|
"CAPACITY": size,
|
||||||
"PARENTID": poolinfo['ID'],
|
"PARENTID": poolinfo['ID'],
|
||||||
"INITIALALLOCCAPACITY": units.Ki * 20,
|
"INITIALALLOCCAPACITY": units.Ki * 20,
|
||||||
|
@ -340,6 +337,25 @@ class V3StorageConnection(driver.HuaweiBase):
|
||||||
"ENABLECOMPRESSION": extra_specs['compression'],
|
"ENABLECOMPRESSION": extra_specs['compression'],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if 'LUNType' in extra_specs:
|
||||||
|
fileparam['ALLOCTYPE'] = extra_specs['LUNType']
|
||||||
|
else:
|
||||||
|
root = self.helper._read_xml()
|
||||||
|
fstype = root.findtext('Filesystem/AllocType')
|
||||||
|
if fstype:
|
||||||
|
fstype = fstype.strip().strip('\n')
|
||||||
|
if fstype == 'Thin':
|
||||||
|
fileparam['ALLOCTYPE'] = constants.ALLOC_TYPE_THIN_FLAG
|
||||||
|
elif fstype == 'Thick':
|
||||||
|
fileparam['ALLOCTYPE'] = constants.ALLOC_TYPE_THICK_FLAG
|
||||||
|
else:
|
||||||
|
err_msg = (_(
|
||||||
|
'Config file is wrong. AllocType type must be set to'
|
||||||
|
' "Thin" or "Thick". AllocType:%(fetchtype)s') %
|
||||||
|
{'fetchtype': fstype})
|
||||||
|
LOG.error(err_msg)
|
||||||
|
raise exception.InvalidShare(reason=err_msg)
|
||||||
|
|
||||||
if fileparam['ALLOCTYPE'] == 0:
|
if fileparam['ALLOCTYPE'] == 0:
|
||||||
if (extra_specs['dedupe'] or
|
if (extra_specs['dedupe'] or
|
||||||
extra_specs['compression']):
|
extra_specs['compression']):
|
||||||
|
@ -619,15 +635,12 @@ class V3StorageConnection(driver.HuaweiBase):
|
||||||
else:
|
else:
|
||||||
opts['thin_provisioning'] = constants.ALLOC_TYPE_THICK
|
opts['thin_provisioning'] = constants.ALLOC_TYPE_THICK
|
||||||
|
|
||||||
if (fs['ALLOCTYPE'] != poolinfo['type']
|
if fs['ALLOCTYPE'] != opts['thin_provisioning']:
|
||||||
or fs['ALLOCTYPE'] != opts['thin_provisioning']):
|
msg = (_("Manage existing share "
|
||||||
msg = (_("Manage existing share fs type and pool type "
|
"fs type and new_share_type mismatch. "
|
||||||
"or fs type and new_share_type mismatch. "
|
"fs type is: %(fs_type)s, "
|
||||||
"fs type is: %(fs_type)s, pool type is: "
|
"new_share_type is: %(new_share_type)s")
|
||||||
"%(pool_type)s, new_share_type is: "
|
|
||||||
"%(new_share_type)s")
|
|
||||||
% {"fs_type": fs['ALLOCTYPE'],
|
% {"fs_type": fs['ALLOCTYPE'],
|
||||||
"pool_type": poolinfo['type'],
|
|
||||||
"new_share_type": opts['thin_provisioning']})
|
"new_share_type": opts['thin_provisioning']})
|
||||||
raise exception.InvalidHost(reason=msg)
|
raise exception.InvalidHost(reason=msg)
|
||||||
else:
|
else:
|
||||||
|
@ -761,8 +774,7 @@ class V3StorageConnection(driver.HuaweiBase):
|
||||||
username = root.findtext('Storage/UserName')
|
username = root.findtext('Storage/UserName')
|
||||||
pwd = root.findtext('Storage/UserPassword')
|
pwd = root.findtext('Storage/UserPassword')
|
||||||
product = root.findtext('Storage/Product')
|
product = root.findtext('Storage/Product')
|
||||||
thin_pool_node = root.findtext('Filesystem/Thin_StoragePool')
|
pool_node = root.findtext('Filesystem/StoragePool')
|
||||||
thick_pool_node = root.findtext('Filesystem/Thick_StoragePool')
|
|
||||||
|
|
||||||
if product != "V3":
|
if product != "V3":
|
||||||
err_msg = (_(
|
err_msg = (_(
|
||||||
|
@ -778,10 +790,10 @@ class V3StorageConnection(driver.HuaweiBase):
|
||||||
LOG.error(err_msg)
|
LOG.error(err_msg)
|
||||||
raise exception.InvalidInput(err_msg)
|
raise exception.InvalidInput(err_msg)
|
||||||
|
|
||||||
if (not thin_pool_node) and (not thick_pool_node):
|
if not pool_node:
|
||||||
err_msg = (_(
|
err_msg = (_(
|
||||||
'check_conf_file: Config file invalid. '
|
'check_conf_file: Config file invalid. '
|
||||||
'Thin_StoragePool or Thick_StoragePool must be set.'))
|
'StoragePool must be set.'))
|
||||||
LOG.error(err_msg)
|
LOG.error(err_msg)
|
||||||
raise exception.InvalidInput(err_msg)
|
raise exception.InvalidInput(err_msg)
|
||||||
|
|
||||||
|
|
|
@ -331,17 +331,6 @@ class RestHelper(object):
|
||||||
|
|
||||||
self._assert_rest_result(result, 'Start CIFS service error.')
|
self._assert_rest_result(result, 'Start CIFS service error.')
|
||||||
|
|
||||||
def _find_pool_type(self, poolinfo):
|
|
||||||
root = self._read_xml()
|
|
||||||
for pool_type in ('Thin', 'Thick'):
|
|
||||||
pool_name_list = root.findtext(('Filesystem/%s_StoragePool'
|
|
||||||
% pool_type))
|
|
||||||
pool_name_list = pool_name_list.split(";")
|
|
||||||
for pool_name in pool_name_list:
|
|
||||||
pool_name = pool_name.strip().strip('\n')
|
|
||||||
if poolinfo['name'] == pool_name:
|
|
||||||
poolinfo['type'] = pool_type
|
|
||||||
|
|
||||||
def _find_pool_info(self, pool_name, result):
|
def _find_pool_info(self, pool_name, result):
|
||||||
if pool_name is None:
|
if pool_name is None:
|
||||||
return
|
return
|
||||||
|
@ -355,7 +344,6 @@ class RestHelper(object):
|
||||||
poolinfo['CAPACITY'] = item['USERFREECAPACITY']
|
poolinfo['CAPACITY'] = item['USERFREECAPACITY']
|
||||||
poolinfo['TOTALCAPACITY'] = item['USERTOTALCAPACITY']
|
poolinfo['TOTALCAPACITY'] = item['USERTOTALCAPACITY']
|
||||||
poolinfo['CONSUMEDCAPACITY'] = item['USERCONSUMEDCAPACITY']
|
poolinfo['CONSUMEDCAPACITY'] = item['USERCONSUMEDCAPACITY']
|
||||||
self._find_pool_type(poolinfo)
|
|
||||||
break
|
break
|
||||||
|
|
||||||
return poolinfo
|
return poolinfo
|
||||||
|
|
|
@ -337,12 +337,6 @@ class FakeHuaweiNasHelper(helper.RestHelper):
|
||||||
"NAME":"OpenStack_Pool",
|
"NAME":"OpenStack_Pool",
|
||||||
"USERTOTALCAPACITY":"4194304",
|
"USERTOTALCAPACITY":"4194304",
|
||||||
"USAGETYPE":"2",
|
"USAGETYPE":"2",
|
||||||
"USERCONSUMEDCAPACITY":"2097152"},
|
|
||||||
{"USERFREECAPACITY":"2097152",
|
|
||||||
"ID":"2",
|
|
||||||
"NAME":"OpenStack_Pool_Thick",
|
|
||||||
"USERTOTALCAPACITY":"4194304",
|
|
||||||
"USAGETYPE":"2",
|
|
||||||
"USERCONSUMEDCAPACITY":"2097152"}]}"""
|
"USERCONSUMEDCAPACITY":"2097152"}]}"""
|
||||||
|
|
||||||
if url == "/filesystem":
|
if url == "/filesystem":
|
||||||
|
@ -1028,6 +1022,17 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||||
self.assertRaises(exception.InvalidInput,
|
self.assertRaises(exception.InvalidInput,
|
||||||
self.driver.get_backend_driver)
|
self.driver.get_backend_driver)
|
||||||
|
|
||||||
|
def test_create_share_nfs_alloctype_fail(self):
|
||||||
|
self.recreate_fake_conf_file(alloctype_value='alloctype_fail')
|
||||||
|
self.driver.plugin.configuration.manila_huawei_conf_file = (
|
||||||
|
self.fake_conf_file)
|
||||||
|
self.driver.plugin.helper.login()
|
||||||
|
self.assertRaises(exception.InvalidShare,
|
||||||
|
self.driver.create_share,
|
||||||
|
self._context,
|
||||||
|
self.share_nfs,
|
||||||
|
self.share_server)
|
||||||
|
|
||||||
def test_create_share_storagepool_not_exist(self):
|
def test_create_share_storagepool_not_exist(self):
|
||||||
self.driver.plugin.helper.login()
|
self.driver.plugin.helper.login()
|
||||||
self.assertRaises(exception.InvalidHost,
|
self.assertRaises(exception.InvalidHost,
|
||||||
|
@ -1095,6 +1100,7 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||||
'share_type_get',
|
'share_type_get',
|
||||||
mock.Mock(return_value=share_type))
|
mock.Mock(return_value=share_type))
|
||||||
self.driver.plugin.helper.login()
|
self.driver.plugin.helper.login()
|
||||||
|
self.recreate_fake_conf_file(alloctype_value='Thin')
|
||||||
self.driver.plugin.configuration.manila_huawei_conf_file = (
|
self.driver.plugin.configuration.manila_huawei_conf_file = (
|
||||||
self.fake_conf_file)
|
self.fake_conf_file)
|
||||||
self.driver.plugin.helper.login()
|
self.driver.plugin.helper.login()
|
||||||
|
@ -1195,6 +1201,7 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||||
self.mock_object(db,
|
self.mock_object(db,
|
||||||
'share_type_get',
|
'share_type_get',
|
||||||
mock.Mock(return_value=share_type))
|
mock.Mock(return_value=share_type))
|
||||||
|
self.recreate_fake_conf_file(alloctype_value='Thin')
|
||||||
self.driver.plugin.configuration.manila_huawei_conf_file = (
|
self.driver.plugin.configuration.manila_huawei_conf_file = (
|
||||||
self.fake_conf_file)
|
self.fake_conf_file)
|
||||||
self.driver.plugin.helper.login()
|
self.driver.plugin.helper.login()
|
||||||
|
@ -1237,7 +1244,7 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||||
self.assertRaises(exception.InvalidShare,
|
self.assertRaises(exception.InvalidShare,
|
||||||
self.driver.create_share,
|
self.driver.create_share,
|
||||||
self._context,
|
self._context,
|
||||||
self.share_nfs_thick,
|
self.share_nfs,
|
||||||
self.share_server)
|
self.share_server)
|
||||||
|
|
||||||
def test_create_share_cache_not_exist(self):
|
def test_create_share_cache_not_exist(self):
|
||||||
|
@ -1400,38 +1407,22 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||||
expected['QoS_support'] = False
|
expected['QoS_support'] = False
|
||||||
expected["snapshot_support"] = False
|
expected["snapshot_support"] = False
|
||||||
expected["pools"] = []
|
expected["pools"] = []
|
||||||
pool_thin = dict(
|
pool = dict(
|
||||||
pool_name='OpenStack_Pool',
|
pool_name='OpenStack_Pool',
|
||||||
total_capacity_gb=2.0,
|
total_capacity_gb=2.0,
|
||||||
free_capacity_gb=1.0,
|
free_capacity_gb=1.0,
|
||||||
allocated_capacity_gb=1.0,
|
allocated_capacity_gb=1.0,
|
||||||
QoS_support=False,
|
QoS_support=False,
|
||||||
reserved_percentage=0,
|
reserved_percentage=0,
|
||||||
compression=True,
|
compression=[True, False],
|
||||||
dedupe=True,
|
dedupe=[True, False],
|
||||||
max_over_subscription_ratio=1,
|
max_over_subscription_ratio=1,
|
||||||
provisioned_capacity_gb=1.0,
|
provisioned_capacity_gb=1.0,
|
||||||
thin_provisioning=True,
|
thin_provisioning=[True, False],
|
||||||
huawei_smartcache=True,
|
huawei_smartcache=[True, False],
|
||||||
huawei_smartpartition=True,
|
huawei_smartpartition=[True, False],
|
||||||
)
|
)
|
||||||
pool_thick = dict(
|
expected["pools"].append(pool)
|
||||||
pool_name='OpenStack_Pool_Thick',
|
|
||||||
total_capacity_gb=2.0,
|
|
||||||
free_capacity_gb=1.0,
|
|
||||||
allocated_capacity_gb=1.0,
|
|
||||||
QoS_support=False,
|
|
||||||
reserved_percentage=0,
|
|
||||||
compression=False,
|
|
||||||
dedupe=False,
|
|
||||||
max_over_subscription_ratio=1,
|
|
||||||
provisioned_capacity_gb=1.0,
|
|
||||||
thin_provisioning=False,
|
|
||||||
huawei_smartcache=True,
|
|
||||||
huawei_smartpartition=True,
|
|
||||||
)
|
|
||||||
expected["pools"].append(pool_thin)
|
|
||||||
expected["pools"].append(pool_thick)
|
|
||||||
self.assertEqual(expected, self.driver._stats)
|
self.assertEqual(expected, self.driver._stats)
|
||||||
|
|
||||||
def test_allow_access_proto_fail(self):
|
def test_allow_access_proto_fail(self):
|
||||||
|
@ -1991,6 +1982,7 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||||
product_flag=True, username_flag=True,
|
product_flag=True, username_flag=True,
|
||||||
pool_node_flag=True, timeout_flag=True,
|
pool_node_flag=True, timeout_flag=True,
|
||||||
wait_interval_flag=True,
|
wait_interval_flag=True,
|
||||||
|
alloctype_value='Thick',
|
||||||
multi_url=False,
|
multi_url=False,
|
||||||
logical_port_ip='100.115.10.68'):
|
logical_port_ip='100.115.10.68'):
|
||||||
doc = xml.dom.minidom.Document()
|
doc = xml.dom.minidom.Document()
|
||||||
|
@ -2042,19 +2034,12 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||||
lun = doc.createElement('Filesystem')
|
lun = doc.createElement('Filesystem')
|
||||||
config.appendChild(lun)
|
config.appendChild(lun)
|
||||||
|
|
||||||
thin_storagepool = doc.createElement('Thin_StoragePool')
|
storagepool = doc.createElement('StoragePool')
|
||||||
if pool_node_flag:
|
if pool_node_flag:
|
||||||
pool_text = doc.createTextNode('OpenStack_Pool;OpenStack_Pool2; ;')
|
pool_text = doc.createTextNode('OpenStack_Pool;OpenStack_Pool2; ;')
|
||||||
else:
|
else:
|
||||||
pool_text = doc.createTextNode('')
|
pool_text = doc.createTextNode('')
|
||||||
thin_storagepool.appendChild(pool_text)
|
storagepool.appendChild(pool_text)
|
||||||
|
|
||||||
thick_storagepool = doc.createElement('Thick_StoragePool')
|
|
||||||
if pool_node_flag:
|
|
||||||
pool_text = doc.createTextNode('OpenStack_Pool_Thick')
|
|
||||||
else:
|
|
||||||
pool_text = doc.createTextNode('')
|
|
||||||
thick_storagepool.appendChild(pool_text)
|
|
||||||
|
|
||||||
timeout = doc.createElement('Timeout')
|
timeout = doc.createElement('Timeout')
|
||||||
|
|
||||||
|
@ -2071,10 +2056,14 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||||
waitinterval_text = doc.createTextNode('')
|
waitinterval_text = doc.createTextNode('')
|
||||||
waitinterval.appendChild(waitinterval_text)
|
waitinterval.appendChild(waitinterval_text)
|
||||||
|
|
||||||
|
alloctype = doc.createElement('AllocType')
|
||||||
|
alloctype_text = doc.createTextNode(alloctype_value)
|
||||||
|
alloctype.appendChild(alloctype_text)
|
||||||
|
|
||||||
lun.appendChild(timeout)
|
lun.appendChild(timeout)
|
||||||
|
lun.appendChild(alloctype)
|
||||||
lun.appendChild(waitinterval)
|
lun.appendChild(waitinterval)
|
||||||
lun.appendChild(thin_storagepool)
|
lun.appendChild(storagepool)
|
||||||
lun.appendChild(thick_storagepool)
|
|
||||||
|
|
||||||
prefetch = doc.createElement('Prefetch')
|
prefetch = doc.createElement('Prefetch')
|
||||||
prefetch.setAttribute('Type', '0')
|
prefetch.setAttribute('Type', '0')
|
||||||
|
@ -2088,6 +2077,7 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||||
def recreate_fake_conf_file(self, product_flag=True, username_flag=True,
|
def recreate_fake_conf_file(self, product_flag=True, username_flag=True,
|
||||||
pool_node_flag=True, timeout_flag=True,
|
pool_node_flag=True, timeout_flag=True,
|
||||||
wait_interval_flag=True,
|
wait_interval_flag=True,
|
||||||
|
alloctype_value='Thick',
|
||||||
multi_url=False,
|
multi_url=False,
|
||||||
logical_port_ip='100.115.10.68'):
|
logical_port_ip='100.115.10.68'):
|
||||||
self.tmp_dir = tempfile.mkdtemp()
|
self.tmp_dir = tempfile.mkdtemp()
|
||||||
|
@ -2096,6 +2086,6 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||||
self.create_fake_conf_file(self.fake_conf_file, product_flag,
|
self.create_fake_conf_file(self.fake_conf_file, product_flag,
|
||||||
username_flag, pool_node_flag,
|
username_flag, pool_node_flag,
|
||||||
timeout_flag, wait_interval_flag,
|
timeout_flag, wait_interval_flag,
|
||||||
multi_url,
|
alloctype_value, multi_url,
|
||||||
logical_port_ip)
|
logical_port_ip)
|
||||||
self.addCleanup(os.remove, self.fake_conf_file)
|
self.addCleanup(os.remove, self.fake_conf_file)
|
||||||
|
|
Loading…
Reference in New Issue