From 5ec17aa800751508468fbab28d4df3040de93f3c Mon Sep 17 00:00:00 2001 From: zhangchao010 Date: Thu, 18 Apr 2013 00:15:24 +0800 Subject: [PATCH] Encode username and password in config file Encode username and password in xml file with base64. And change lun owning controller when attaching the lun to get better performance. Fixes bug: 1136892 Change-Id: Iad79d1ec1651e3582b86e865f0342fdc55065134 --- cinder/tests/test_huawei.py | 109 +++++++++++++------ cinder/volume/drivers/huawei/huawei_iscsi.py | 64 +++++++++-- 2 files changed, 131 insertions(+), 42 deletions(-) diff --git a/cinder/tests/test_huawei.py b/cinder/tests/test_huawei.py index a88023c5b..fd3914b92 100644 --- a/cinder/tests/test_huawei.py +++ b/cinder/tests/test_huawei.py @@ -18,6 +18,11 @@ """ Tests for HUAWEI volume driver. """ +import mox +import os +import shutil +import tempfile +from xml.dom.minidom import Document from xml.etree import ElementTree as ET from cinder import exception @@ -28,30 +33,6 @@ from cinder.volume.drivers.huawei import huawei_iscsi LOG = logging.getLogger(__name__) -FakeXML = """ - - - 10.10.10.1 - 10.10.10.2 - admin - 123456 - - - Thick - 64 - 1 - 1 - - - - - - 192.168.100.1 - - -""" - LUNInfo = {'ID': None, 'Name': None, 'Size': None, @@ -185,13 +166,21 @@ class HuaweiVolumeTestCase(test.TestCase): def __init__(self, *args, **kwargs): super(HuaweiVolumeTestCase, self).__init__(*args, **kwargs) - self.driver = FakeHuaweiStorage(configuration=conf.Configuration(None)) + + self.tmp_dir = tempfile.mkdtemp() + self.fake_conf_file = self.tmp_dir + '/cinder_huawei_conf.xml' + self._create_fake_conf_file() + configuration = mox.MockObject(conf.Configuration) + configuration.cinder_huawei_conf_file = self.fake_conf_file + configuration.append_config_values(mox.IgnoreArg()) + self.driver = FakeHuaweiStorage(configuration=configuration) + self.driver.do_setup({}) - self.driver._test_flg = 'check_for_fail' - self._test_check_for_setup_errors() def setUp(self): super(HuaweiVolumeTestCase, self).setUp() + self.driver._test_flg = 'check_for_fail' + self._test_check_for_setup_errors() def test_create_export_failed(self): self.assertRaises(exception.VolumeBackendAPIException, @@ -268,6 +257,60 @@ class HuaweiVolumeTestCase(test.TestCase): self._test_delete_snapshot() self._test_delete_volume() + def cleanup(self): + if os.path.exists(self.fake_conf_file): + os.remove(self.fake_conf_file) + shutil.rmtree(self.tmp_dir) + + def _create_fake_conf_file(self): + doc = Document() + + config = doc.createElement('config') + doc.appendChild(config) + + storage = doc.createElement('Storage') + config.appendChild(storage) + controllerip0 = doc.createElement('ControllerIP0') + controllerip0_text = doc.createTextNode('10.10.10.1') + controllerip0.appendChild(controllerip0_text) + storage.appendChild(controllerip0) + controllerip1 = doc.createElement('ControllerIP1') + controllerip1_text = doc.createTextNode('10.10.10.2') + controllerip1.appendChild(controllerip1_text) + storage.appendChild(controllerip1) + username = doc.createElement('UserName') + username_text = doc.createTextNode('admin') + username.appendChild(username_text) + storage.appendChild(username) + userpassword = doc.createElement('UserPassword') + userpassword_text = doc.createTextNode('123456') + userpassword.appendChild(userpassword_text) + storage.appendChild(userpassword) + + lun = doc.createElement('LUN') + config.appendChild(lun) + storagepool = doc.createElement('StoragePool') + storagepool.setAttribute('Name', 'RAID_001') + lun.appendChild(storagepool) + storagepool = doc.createElement('StoragePool') + storagepool.setAttribute('Name', 'RAID_002') + lun.appendChild(storagepool) + + iscsi = doc.createElement('iSCSI') + config.appendChild(iscsi) + defaulttargetip = doc.createElement('DefaultTargetIP') + defaulttargetip_text = doc.createTextNode('192.168.100.1') + defaulttargetip.appendChild(defaulttargetip_text) + iscsi.appendChild(defaulttargetip) + initiator = doc.createElement('Initiator') + initiator.setAttribute('Name', 'iqn.1993-08.debian:01:ec2bff7ac3a3') + initiator.setAttribute('TargetIP', '192.168.100.2') + iscsi.appendChild(initiator) + + file = open(self.fake_conf_file, 'w') + file.write(doc.toprettyxml(indent='')) + file.close() + def _test_check_for_setup_errors(self): self.driver.check_for_setup_error() @@ -806,13 +849,11 @@ Link Status Multipath Type ============================================================================ """ + elif cmd == 'chglun': + out = 'command operates successfully' + out = out.replace('\n', '\r\n') return out - def _read_xml(self): - try: - root = ET.fromstring(FakeXML) - except Exception as err: - LOG.debug(_('_read_xml:ERROR:%s') % err) - raise exception.VolumeBackendAPIException(data=err) - return root + def _get_lun_controller(self, lunid): + pass diff --git a/cinder/volume/drivers/huawei/huawei_iscsi.py b/cinder/volume/drivers/huawei/huawei_iscsi.py index b6f51bcdb..6eb4a957c 100644 --- a/cinder/volume/drivers/huawei/huawei_iscsi.py +++ b/cinder/volume/drivers/huawei/huawei_iscsi.py @@ -17,6 +17,7 @@ """ Volume driver for HUAWEI T series and Dorado storage systems. """ +import base64 import os import paramiko import re @@ -253,7 +254,7 @@ class HuaweiISCSIDriver(driver.ISCSIDriver): raise exception.VolumeBackendAPIException(data=err_msg) target_ip = iscsi_conf['DefaultTargetIP'] - target_iqn = self._get_tgt_iqn(target_ip) + (target_iqn, controller) = self._get_tgt_iqn(target_ip) if not target_iqn: err_msg = (_('initialize_connection:Failed to find target iSCSI' 'iqn. Target IP:%(ip)s') @@ -329,6 +330,10 @@ class HuaweiISCSIDriver(driver.ISCSIDriver): self._map_lun(lun_id, host_id, new_hostlun_id) hostlun_id = self._get_hostlunid(host_id, lun_id) + # Change lun ownning controller for better performance. + if self._get_lun_controller(lun_id) != controller: + self._change_lun_controller(lun_id, controller) + # Return iSCSI properties. properties = {} properties['target_discovered'] = False @@ -583,12 +588,29 @@ class HuaweiISCSIDriver(driver.ISCSIDriver): def _get_login_info(self): """Get login IP, username and password from config file.""" logininfo = {} - root = self._read_xml() try: + filename = self.configuration.cinder_huawei_conf_file + tree = ET.parse(filename) + root = tree.getroot() logininfo['ControllerIP0'] = root.findtext('Storage/ControllerIP0') logininfo['ControllerIP1'] = root.findtext('Storage/ControllerIP1') - logininfo['UserName'] = root.findtext('Storage/UserName') - logininfo['UserPassword'] = root.findtext('Storage/UserPassword') + + need_encode = False + for key in ['UserName', 'UserPassword']: + node = root.find('Storage/%s' % key) + node_text = node.text + if node_text.find('!$$$') == 0: + logininfo[key] = base64.b64decode(node_text[4:]) + else: + logininfo[key] = node_text + node.text = '!$$$' + base64.b64encode(node_text) + need_encode = True + if need_encode: + try: + tree.write(filename, 'UTF-8') + except Exception as err: + LOG.error(_('Write login informationto xml error. %s') + % err) except Exception as err: LOG.error(_('_get_login_info error. %s') % err) @@ -996,7 +1018,7 @@ class HuaweiISCSIDriver(driver.ISCSIDriver): out = self._execute_cli(cli_cmd) en = out.split('\r\n') if len(en) < 4: - return None + return (None, None) index = en[4].find('iqn') iqn_prefix = en[4][index:] @@ -1026,9 +1048,9 @@ class HuaweiISCSIDriver(driver.ISCSIDriver): LOG.debug(_('_get_tgt_iqn:iSCSI target iqn is:%s') % iqn) - return iqn + return (iqn, iscsiip_info['ctrid']) else: - return None + return (None, None) def _get_iscsi_ip_info(self, iscsiip): """Get iSCSI IP infomation of storage device.""" @@ -1128,7 +1150,7 @@ class HuaweiISCSIDriver(driver.ISCSIDriver): """Get map infomation of the given host. This method return a map information list. Every item in the list - is a dictionary. The dictionarie includes three keys: mapid, + is a dictionary. The dictionary includes three keys: mapid, devlunid, hostlunid. These items are sorted by hostlunid value from small to large. """ @@ -1426,6 +1448,32 @@ class HuaweiISCSIDriver(driver.ISCSIDriver): return r[1] return None + def _get_lun_controller(self, lun_id): + cli_cmd = ('showlun -lun %s' % lun_id) + out = self._execute_cli(cli_cmd) + en = out.split('\r\n') + if len(en) <= 4: + return None + + if "Dorado2100 G2" == self.device_type['type']: + return en[10].split()[3] + else: + return en[12].split()[3] + + def _change_lun_controller(self, lun_id, controller): + cli_cmd = ('chglun -lun %s -c %s' % (lun_id, controller)) + out = self._execute_cli(cli_cmd) + if not re.search('command operates successfully', out): + err_msg = (_('_change_lun_controller:Failed to change lun owning' + 'controller. lun id:%(lunid)s. ' + 'new controller:%(controller)s. ' + 'out:%(out)s') + % {'lunid': lun_id, + 'controller': controller, + 'out': out}) + LOG.error(err_msg) + raise exception.VolumeBackendAPIException(data=err_msg) + def _is_resource_pool_enough(self): """Check whether resource pools' valid size is more than 1G.""" cli_cmd = ('showrespool') -- 2.45.2