Merge "Modify the configuration mode of FusionStorage Cinder Driver"

This commit is contained in:
Zuul 2019-03-18 18:37:25 +00:00 committed by Gerrit Code Review
commit 483b037b69
5 changed files with 150 additions and 74 deletions

View File

@ -15,6 +15,7 @@
import ddt
import mock
import os
import shutil
import tempfile
@ -43,52 +44,108 @@ class FusionStorageConfTestCase(test.TestCase):
self.tmp_dir + '/cinder.conf')
config = configparser.ConfigParser()
config.add_section('storage')
config.set('storage', 'RestURL', 'https://fake_rest_site')
config.set('storage', 'UserName', 'fake_user')
config.set('storage', 'Password', 'fake_passwd')
config.set('storage', 'StoragePool', 'fake_pool')
config.add_section('backend_name')
config.set('backend_name', 'dsware_rest_url', 'https://fake_rest_site')
config.set('backend_name', 'san_login', 'fake_user')
config.set('backend_name', 'san_password', 'fake_passwd')
config.set('backend_name', 'dsware_storage_pools', 'fake_pool')
config.add_section('manager_ip')
config.set('manager_ip', 'fake_host', 'fake_ip')
config.write(open(self.conf.cinder_fusionstorage_conf_file, 'w'))
def test_update_config_value(self):
@mock.patch.object(fs_conf.FusionStorageConf, '_encode_authentication')
@mock.patch.object(fs_conf.FusionStorageConf, '_pools_name')
@mock.patch.object(fs_conf.FusionStorageConf, '_san_address')
@mock.patch.object(fs_conf.FusionStorageConf, '_san_user')
@mock.patch.object(fs_conf.FusionStorageConf, '_san_password')
def test_update_config_value(self, mock_san_password, mock_san_user,
mock_san_address, mock_pools_name,
mock_encode_authentication):
self.fusionstorage_conf.update_config_value()
mock_encode_authentication.assert_called_once_with()
mock_pools_name.assert_called_once_with()
mock_san_address.assert_called_once_with()
mock_san_user.assert_called_once_with()
mock_san_password.assert_called_once_with()
@mock.patch.object(os.path, 'exists')
def test__encode_authentication(self, mock_exists):
config = configparser.ConfigParser()
config.read(self.conf.cinder_fusionstorage_conf_file)
storage_info = {'RestURL': config.get('storage', 'RestURL'),
'UserName': config.get('storage', 'UserName'),
'Password': config.get('storage', 'Password'),
'StoragePool': config.get('storage', 'StoragePool')}
mock_exists.return_value = False
user_name = 'fake_user'
self.mock_object(
self.fusionstorage_conf.configuration, 'safe_get',
return_value=storage_info)
return_value=user_name)
self.fusionstorage_conf._encode_authentication()
self.fusionstorage_conf.update_config_value()
password = 'fake_passwd'
self.mock_object(
self.fusionstorage_conf.configuration, 'safe_get',
return_value=password)
self.fusionstorage_conf._encode_authentication()
@mock.patch.object(os.path, 'exists')
@mock.patch.object(configparser.ConfigParser, 'set')
def test__rewrite_conf(self, mock_set, mock_exists):
mock_exists.return_value = False
mock_set.return_value = "success"
self.fusionstorage_conf._rewrite_conf('fake_name', 'fake_pwd')
def test__san_address(self):
address = 'https://fake_rest_site'
self.mock_object(
self.fusionstorage_conf.configuration, 'safe_get',
return_value=address)
self.fusionstorage_conf._san_address()
self.assertEqual('https://fake_rest_site',
self.fusionstorage_conf.configuration.san_address)
def test__san_user(self):
user = '!&&&ZmFrZV91c2Vy'
self.mock_object(
self.fusionstorage_conf.configuration, 'safe_get',
return_value=user)
self.fusionstorage_conf._san_user()
self.assertEqual(
'fake_user', self.fusionstorage_conf.configuration.san_user)
user = 'fake_user_2'
self.mock_object(
self.fusionstorage_conf.configuration, 'safe_get',
return_value=user)
self.fusionstorage_conf._san_user()
self.assertEqual(
'fake_user_2', self.fusionstorage_conf.configuration.san_user)
def test__san_password(self):
password = '!&&&ZmFrZV9wYXNzd2Q='
self.mock_object(
self.fusionstorage_conf.configuration, 'safe_get',
return_value=password)
self.fusionstorage_conf._san_password()
self.assertEqual(
'fake_passwd', self.fusionstorage_conf.configuration.san_password)
password = 'fake_passwd_2'
self.mock_object(
self.fusionstorage_conf.configuration, 'safe_get',
return_value=password)
self.fusionstorage_conf._san_password()
self.assertEqual('fake_passwd_2',
self.fusionstorage_conf.configuration.san_password)
def test__pools_name(self):
pools_name = 'fake_pool'
self.mock_object(
self.fusionstorage_conf.configuration, 'safe_get',
return_value=pools_name)
self.fusionstorage_conf._pools_name()
self.assertListEqual(
['fake_pool'], self.fusionstorage_conf.configuration.pools_name)
def test__encode_authentication(self):
config = configparser.ConfigParser()
config.read(self.conf.cinder_fusionstorage_conf_file)
storage_info = {'RestURL': config.get('storage', 'RestURL'),
'UserName': config.get('storage', 'UserName'),
'Password': config.get('storage', 'Password'),
'StoragePool': config.get('storage', 'StoragePool')}
self.fusionstorage_conf._encode_authentication(storage_info)
name_node = storage_info.get('UserName')
pwd_node = storage_info.get('Password')
self.assertEqual('!&&&ZmFrZV91c2Vy', name_node)
self.assertEqual('!&&&ZmFrZV9wYXNzd2Q=', pwd_node)
def test__manager_ip(self):
manager_ips = {'fake_host': 'fake_ip'}
self.mock_object(

View File

@ -23,9 +23,8 @@ VOLUME_NOT_EXIST = 31000000
BASIC_URI = '/dsware/service/'
CONF_PATH = "/etc/cinder/cinder.conf"
CONF_ADDRESS = "RestURL"
CONF_ADDRESS = "dsware_rest_url"
CONF_MANAGER_IP = "manager_ips"
CONF_POOLS = "StoragePool"
CONF_PWD = "Password"
CONF_STORAGE = "storage"
CONF_USER = "UserName"
CONF_POOLS = "dsware_storage_pools"
CONF_PWD = "san_password"
CONF_USER = "san_login"

View File

@ -25,6 +25,7 @@ from cinder import interface
from cinder.volume import driver
from cinder.volume.drivers.fusionstorage import fs_client
from cinder.volume.drivers.fusionstorage import fs_conf
from cinder.volume.drivers.san import san
from cinder.volume import utils as volume_utils
LOG = logging.getLogger(__name__)
@ -89,13 +90,15 @@ volume_opts = [
help='This option is to support the FSA to mount across the '
'different nodes. The parameters takes the standard dict '
'config form, manager_ips = host1:ip1, host2:ip2...'),
cfg.DictOpt('storage',
default={},
secret=True,
help='This field is configured with the information of array '
'and user info. The parameters takes the standard dict '
'config form, Storage = UserName:xxx, Password:xxx, '
'RestURL:xxx')
cfg.StrOpt('dsware_rest_url',
default='',
help='The address of FusionStorage array. For example, '
'"dsware_rest_url=xxx"'),
cfg.StrOpt('dsware_storage_pools',
default="",
help='The list of pools on the FusionStorage array, the '
'semicolon(;) was used to split the storage pools, '
'"dsware_storage_pools = xxx1; xxx2; xxx3"')
]
CONF = cfg.CONF
@ -116,6 +119,7 @@ class DSWAREDriver(driver.VolumeDriver):
raise exception.InvalidInput(reason=msg)
self.configuration.append_config_values(volume_opts)
self.configuration.append_config_values(san.san_opts)
self.conf = fs_conf.FusionStorageConf(self.configuration, self.host)
self.client = None

View File

@ -44,16 +44,15 @@ class FusionStorageConf(object):
raise exception.InvalidInput(reason=msg)
def update_config_value(self):
storage_info = self.configuration.safe_get(constants.CONF_STORAGE)
self._pools_name(storage_info)
self._san_address(storage_info)
self._encode_authentication(storage_info)
self._san_user(storage_info)
self._san_password(storage_info)
self._encode_authentication()
self._pools_name()
self._san_address()
self._san_user()
self._san_password()
def _encode_authentication(self, storage_info):
name_node = storage_info.get(constants.CONF_USER)
pwd_node = storage_info.get(constants.CONF_PWD)
def _encode_authentication(self):
name_node = self.configuration.safe_get(constants.CONF_USER)
pwd_node = self.configuration.safe_get(constants.CONF_PWD)
need_encode = False
if name_node is not None and not name_node.startswith('!&&&'):
@ -67,29 +66,18 @@ class FusionStorageConf(object):
need_encode = True
if need_encode:
self._rewrite_conf(storage_info, name_node, pwd_node)
self._rewrite_conf(name_node, pwd_node)
def _rewrite_conf(self, storage_info, name_node, pwd_node):
storage_info.update({constants.CONF_USER: name_node,
constants.CONF_PWD: pwd_node})
storage_info = ("\n %(conf_name)s: %(name)s,"
"\n %(conf_pwd)s: %(pwd)s,"
"\n %(conf_url)s: %(url)s,"
"\n %(conf_pool)s: %(pool)s"
% {"conf_name": constants.CONF_USER,
"conf_pwd": constants.CONF_PWD,
"conf_url": constants.CONF_ADDRESS,
"conf_pool": constants.CONF_POOLS,
"name": name_node,
"pwd": pwd_node,
"url": storage_info.get(constants.CONF_ADDRESS),
"pool": storage_info.get(constants.CONF_POOLS)})
def _rewrite_conf(self, name_node, pwd_node):
if os.path.exists(constants.CONF_PATH):
utils.execute("chmod", "666", constants.CONF_PATH,
run_as_root=True)
conf = configparser.ConfigParser()
conf.read(constants.CONF_PATH)
conf.set(self.host, constants.CONF_STORAGE, storage_info)
if name_node:
conf.set(self.host, constants.CONF_USER, name_node)
if pwd_node:
conf.set(self.host, constants.CONF_PWD, pwd_node)
fh = open(constants.CONF_PATH, 'w')
conf.write(fh)
fh.close()
@ -102,25 +90,29 @@ class FusionStorageConf(object):
LOG.error(msg)
raise exception.InvalidInput(reason=msg)
def _san_address(self, storage_info):
address = storage_info.get(constants.CONF_ADDRESS)
def _san_address(self):
address = self.configuration.safe_get(constants.CONF_ADDRESS)
self._assert_text_result(address, mess=constants.CONF_ADDRESS)
setattr(self.configuration, 'san_address', address)
def _san_user(self, storage_info):
user_text = storage_info.get(constants.CONF_USER)
def _decode_text(self, text):
return (base64.b64decode(six.b(text[4:])).decode() if
text.startswith('!&&&') else text)
def _san_user(self):
user_text = self.configuration.safe_get(constants.CONF_USER)
self._assert_text_result(user_text, mess=constants.CONF_USER)
user = base64.b64decode(six.b(user_text[4:])).decode()
user = self._decode_text(user_text)
setattr(self.configuration, 'san_user', user)
def _san_password(self, storage_info):
pwd_text = storage_info.get(constants.CONF_PWD)
def _san_password(self):
pwd_text = self.configuration.safe_get(constants.CONF_PWD)
self._assert_text_result(pwd_text, mess=constants.CONF_PWD)
pwd = base64.b64decode(six.b(pwd_text[4:])).decode()
pwd = self._decode_text(pwd_text)
setattr(self.configuration, 'san_password', pwd)
def _pools_name(self, storage_info):
pools_name = storage_info.get(constants.CONF_POOLS)
def _pools_name(self):
pools_name = self.configuration.safe_get(constants.CONF_POOLS)
self._assert_text_result(pools_name, mess=constants.CONF_POOLS)
pools = set(x.strip() for x in pools_name.split(';') if x.strip())
if not pools:

View File

@ -0,0 +1,24 @@
---
upgrades:
- The FusionStorage driver has added the configuration options "manager_ips",
"dsware_rest_url", "san_login", "san_password" and "dsware_storage_pools".
"[<backend_id>]/manager_ips", the ips of FusionStorage Agent(FSA). This
option is to support FSA to mount accross the different FSA nodes. The
parameters takes the standard dict config form, manager_ips = host1:ip1,
host2:ip2...
"[<backend_id>]/dsware_rest_url", the address and port of FusionStorage
Manager(FSM) in the format of a string. Currently, only one "dsware_rest_url"
is supported.
"[<backend_id>]/san_login", the user name of the FusionStorage Manager(FSM)
in the format of a string. Currently, only one "san_login" is supported.
"[<backend_id>]/san_password", the user password of FusionStorage Manager(FSM)
in the format of a string. Currently, only one "san_password" is supported.
"[<backend_id>]/dsware_storage_pools", the name of the storage pools that
exists on the FusionStorage Manager. Multiple storage pools can be configed,
separated by a semicolon.
deprecations:
- The FusionStorage driver has deprecated the configuration options
"dsware_isthin", "dsware_manager", "fusionstorageagent",
"clone_volume_timeout", "pool_type", and "pool_id_filter". These configuration
options will be removed in the Train release(14.0.0).