]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Encode username and password in config file
authorzhangchao010 <zhangchao010@huawei.com>
Wed, 17 Apr 2013 16:15:24 +0000 (00:15 +0800)
committerzhangchao010 <zhangchao010@huawei.com>
Thu, 25 Apr 2013 15:54:48 +0000 (23:54 +0800)
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
cinder/volume/drivers/huawei/huawei_iscsi.py

index a88023c5b26ac6ed05cc01a6ab88d8a756f9609d..fd3914b9277a53e6f1d2f3c9146b58d7b7103650 100644 (file)
 """
 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 = """<?xml version="1.0" encoding="UTF-8" ?>
-<config>
-    <Storage>
-        <ControllerIP0>10.10.10.1</ControllerIP0>
-        <ControllerIP1>10.10.10.2</ControllerIP1>
-        <UserName>admin</UserName>
-        <UserPassword>123456</UserPassword>
-    </Storage>
-    <LUN>
-        <LUNType>Thick</LUNType>
-        <StripUnitSize>64</StripUnitSize>
-        <WriteType>1</WriteType>
-        <MirrorSwitch>1</MirrorSwitch>
-        <Prefetch Type="3" Value="0"/>
-        <StoragePool Name="RAID_001"/>
-        <StoragePool Name="RAID_002"/>
-    </LUN>
-    <iSCSI>
-        <DefaultTargetIP>192.168.100.1</DefaultTargetIP>
-        <Initiator Name="iqn.1993-08.debian:01:ec2bff7ac3a3"
-        TargetIP="192.168.100.2"/>
-    </iSCSI>
-</config>"""
-
 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
index b6f51bcdbe621b6fd3c3803ca8f2f03c9650b403..6eb4a957cee6186e47253ebc22461bfc94ee78be 100644 (file)
@@ -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')