Browse Source

Fix Huawei drivers to support other host OSs

Huawei drivers create Linux hosts by default when attaching volumes.
This patch makes them also support Windows, XenServer, AIX, etc.
The default OS is still Linux if it is not specified.

Users need to configure the host OS types in Huawei XML configuration
file. They need to set the items like this:
<Host OSType="Windows" HostIP="10.10.0.1, 10.10.0.2, ..." />
<Host .../>

When attaching a volume, the driver will get the host IP from nova. We
compare that IP with the IP in "HostIP" to get the corresponding OS type.

Closes-bug: #1229759

(cherry picked from I36fd52b97f790f1c68eaf24b6c12e7ef5d16145d)

Change-Id: I6792aaae050b126088447a0df65e10c425b84102
tags/2013.2.4
zhangchao010 5 years ago
parent
commit
0d9f2594fd

+ 2
- 1
cinder/tests/test_huawei_hvs.py View File

@@ -61,7 +61,8 @@ test_snap = {'name': 'volume-21ec7341-9256-497b-97d9-ef48edcf0635',
61 61
 FakeConnector = {'initiator': 'iqn.1993-08.debian:01:ec2bff7ac3a3',
62 62
                  'wwpns': ['10000090fa0d6754'],
63 63
                  'wwnns': ['10000090fa0d6755'],
64
-                 'host': 'fakehost'}
64
+                 'host': 'fakehost',
65
+                 'ip': '10.10.0.1'}
65 66
 
66 67
 
67 68
 def Fake_sleep(time):

+ 71
- 1
cinder/tests/test_huawei_t_dorado.py View File

@@ -34,6 +34,7 @@ from cinder import exception
34 34
 from cinder import test
35 35
 from cinder import utils
36 36
 from cinder.volume import configuration as conf
37
+from cinder.volume.drivers.huawei import huawei_utils
37 38
 from cinder.volume.drivers.huawei import HuaweiVolumeDriver
38 39
 from cinder.volume.drivers.huawei import ssh_common
39 40
 from cinder.volume import volume_types
@@ -150,7 +151,8 @@ FAKE_SNAPSHOT = {'name': 'keke34fe-223f-dd33-4423-asdfghjklqwf',
150 151
 FAKE_CONNECTOR = {'initiator': 'iqn.1993-08.debian:01:ec2bff7ac3a3',
151 152
                   'wwpns': ['1000000164s45126'],
152 153
                   'wwnns': ['2000666666666565'],
153
-                  'host': 'fakehost'}
154
+                  'host': 'fakehost',
155
+                  'ip': '10.10.0.1'}
154 156
 
155 157
 RESPOOL_A_SIM = {'Size': '10240', 'Valid Size': '5120'}
156 158
 RESPOOL_B_SIM = {'Size': '10240', 'Valid Size': '10240'}
@@ -300,6 +302,11 @@ def create_fake_conf_file(filename):
300 302
     initiator.setAttribute('TargetIP', '192.168.100.2')
301 303
     iscsi.appendChild(initiator)
302 304
 
305
+    os_type = doc.createElement('Host')
306
+    os_type.setAttribute('OSType', 'Linux')
307
+    os_type.setAttribute('HostIP', '10.10.0.1')
308
+    config.appendChild(os_type)
309
+
303 310
     tmp_file = open(filename, 'w')
304 311
     tmp_file.write(doc.toprettyxml(indent=''))
305 312
     tmp_file.close()
@@ -1080,6 +1087,13 @@ class HuaweiTISCSIDriverTestCase(test.TestCase):
1080 1087
         self.assertRaises(exception.InvalidInput,
1081 1088
                           tmp_driver.create_volume, FAKE_VOLUME)
1082 1089
         modify_conf(self.fake_conf_file, 'LUN/LUNType', 'Thick')
1090
+        # Test OSType invalid
1091
+        modify_conf(self.fake_conf_file, 'Host', 'invalid_type',
1092
+                    attrib='OSType')
1093
+        tmp_driver = HuaweiVolumeDriver(configuration=self.configuration)
1094
+        self.assertRaises(exception.InvalidInput,
1095
+                          tmp_driver.do_setup, None)
1096
+        modify_conf(self.fake_conf_file, 'Host', 'Linux', attrib='OSType')
1083 1097
         # Test TargetIP not found
1084 1098
         modify_conf(self.fake_conf_file, 'iSCSI/DefaultTargetIP', '')
1085 1099
         modify_conf(self.fake_conf_file, 'iSCSI/Initiator', '', attrib='Name')
@@ -1643,3 +1657,59 @@ class SSHMethodTestCase(test.TestCase):
1643 1657
 
1644 1658
     def _fake_recv2(self, nBytes):
1645 1659
         raise socket.timeout()
1660
+
1661
+
1662
+class HuaweiUtilsTestCase(test.TestCase):
1663
+    def __init__(self, *args, **kwargs):
1664
+        super(HuaweiUtilsTestCase, self).__init__(*args, **kwargs)
1665
+
1666
+    def setUp(self):
1667
+        super(HuaweiUtilsTestCase, self).setUp()
1668
+
1669
+        self.tmp_dir = tempfile.mkdtemp()
1670
+        self.fake_conf_file = self.tmp_dir + '/cinder_huawei_conf.xml'
1671
+        create_fake_conf_file(self.fake_conf_file)
1672
+
1673
+    def tearDown(self):
1674
+        if os.path.exists(self.fake_conf_file):
1675
+            os.remove(self.fake_conf_file)
1676
+        shutil.rmtree(self.tmp_dir)
1677
+        super(HuaweiUtilsTestCase, self).tearDown()
1678
+
1679
+    def test_parse_xml_file_ioerror(self):
1680
+        tmp_fonf_file = '/xxx/cinder_huawei_conf.xml'
1681
+        self.assertRaises(IOError, huawei_utils.parse_xml_file, tmp_fonf_file)
1682
+
1683
+    def test_is_xml_item_exist(self):
1684
+        root = huawei_utils.parse_xml_file(self.fake_conf_file)
1685
+        res = huawei_utils.is_xml_item_exist(root, 'Storage/UserName')
1686
+        self.assertTrue(res)
1687
+        res = huawei_utils.is_xml_item_exist(root, 'xxx')
1688
+        self.assertFalse(res)
1689
+        res = huawei_utils.is_xml_item_exist(root, 'LUN/StoragePool', 'Name')
1690
+        self.assertTrue(res)
1691
+        res = huawei_utils.is_xml_item_exist(root, 'LUN/StoragePool', 'xxx')
1692
+        self.assertFalse(res)
1693
+
1694
+    def test_is_xml_item_valid(self):
1695
+        root = huawei_utils.parse_xml_file(self.fake_conf_file)
1696
+        res = huawei_utils.is_xml_item_valid(root, 'LUN/LUNType',
1697
+                                             ['Thin', 'Thick'])
1698
+        self.assertTrue(res)
1699
+        res = huawei_utils.is_xml_item_valid(root, 'LUN/LUNType', ['test'])
1700
+        self.assertFalse(res)
1701
+        res = huawei_utils.is_xml_item_valid(root, 'Host',
1702
+                                             ['Linux', 'Windows'], 'OSType')
1703
+        self.assertTrue(res)
1704
+        res = huawei_utils.is_xml_item_valid(root, 'Host', ['test'], 'OSType')
1705
+        self.assertFalse(res)
1706
+
1707
+    def test_get_conf_host_os_type(self):
1708
+        # Default os is Linux
1709
+        res = huawei_utils.get_conf_host_os_type('10.10.10.1',
1710
+                                                 self.fake_conf_file)
1711
+        self.assertEqual(res, '0')
1712
+        modify_conf(self.fake_conf_file, 'Host', 'Windows', 'OSType')
1713
+        res = huawei_utils.get_conf_host_os_type(FAKE_CONNECTOR['ip'],
1714
+                                                 self.fake_conf_file)
1715
+        self.assertEqual(res, '1')

+ 2
- 2
cinder/volume/drivers/huawei/__init__.py View File

@@ -30,7 +30,7 @@ from cinder.volume import driver
30 30
 from cinder.volume.drivers.huawei import huawei_dorado
31 31
 from cinder.volume.drivers.huawei import huawei_hvs
32 32
 from cinder.volume.drivers.huawei import huawei_t
33
-from cinder.volume.drivers.huawei import ssh_common
33
+from cinder.volume.drivers.huawei import huawei_utils
34 34
 
35 35
 LOG = logging.getLogger(__name__)
36 36
 
@@ -78,7 +78,7 @@ class HuaweiVolumeDriver(object):
78 78
 
79 79
     def _get_conf_info(self, filename):
80 80
         """Get product type and connection protocol from config file."""
81
-        root = ssh_common.parse_xml_file(filename)
81
+        root = huawei_utils.parse_xml_file(filename)
82 82
         product = root.findtext('Storage/Product').strip()
83 83
         protocol = root.findtext('Storage/Protocol').strip()
84 84
         if (product in self._product.keys() and

+ 1
- 1
cinder/volume/drivers/huawei/huawei_dorado.py View File

@@ -81,7 +81,7 @@ class HuaweiDoradoFCDriver(huawei_t.HuaweiTFCDriver):
81 81
 
82 82
         self.common._update_login_info()
83 83
         # First, add a host if it is not added before.
84
-        host_id = self.common.add_host(connector['host'])
84
+        host_id = self.common.add_host(connector['host'], connector['ip'])
85 85
         # Then, add free FC ports to the host.
86 86
         ini_wwns = connector['wwpns']
87 87
         free_wwns = self._get_connected_free_wwns()

+ 1
- 1
cinder/volume/drivers/huawei/huawei_hvs.py View File

@@ -34,11 +34,11 @@ class HuaweiHVSISCSIDriver(driver.ISCSIDriver):
34 34
     def do_setup(self, context):
35 35
         """Instantiate common class and log in storage system."""
36 36
         self.common = HVSCommon(configuration=self.configuration)
37
-        self.common.login()
38 37
 
39 38
     def check_for_setup_error(self):
40 39
         """Check configuration  file."""
41 40
         self.common._check_conf_file()
41
+        self.common.login()
42 42
 
43 43
     def create_volume(self, volume):
44 44
         """Create a volume."""

+ 4
- 3
cinder/volume/drivers/huawei/huawei_t.py View File

@@ -25,6 +25,7 @@ import time
25 25
 from cinder import exception
26 26
 from cinder.openstack.common import log as logging
27 27
 from cinder.volume import driver
28
+from cinder.volume.drivers.huawei import huawei_utils
28 29
 from cinder.volume.drivers.huawei import ssh_common
29 30
 
30 31
 
@@ -106,7 +107,7 @@ class HuaweiTISCSIDriver(driver.ISCSIDriver):
106 107
             self._get_iscsi_params(connector['initiator'])
107 108
 
108 109
         # First, add a host if not added before.
109
-        host_id = self.common.add_host(connector['host'],
110
+        host_id = self.common.add_host(connector['host'], connector['ip'],
110 111
                                        connector['initiator'])
111 112
 
112 113
         # Then, add the iSCSI port to the host.
@@ -175,7 +176,7 @@ class HuaweiTISCSIDriver(driver.ISCSIDriver):
175 176
         """
176 177
 
177 178
         iscsiinfo = {}
178
-        root = ssh_common.parse_xml_file(filename)
179
+        root = huawei_utils.parse_xml_file(filename)
179 180
 
180 181
         default_ip = root.findtext('iSCSI/DefaultTargetIP')
181 182
         if default_ip:
@@ -441,7 +442,7 @@ class HuaweiTFCDriver(driver.FibreChannelDriver):
441 442
 
442 443
         self.common._update_login_info()
443 444
         # First, add a host if it is not added before.
444
-        host_id = self.common.add_host(connector['host'])
445
+        host_id = self.common.add_host(connector['host'], connector['ip'])
445 446
         # Then, add free FC ports to the host.
446 447
         ini_wwns = connector['wwpns']
447 448
         free_wwns = self._get_connected_free_wwns()

+ 135
- 0
cinder/volume/drivers/huawei/huawei_utils.py View File

@@ -0,0 +1,135 @@
1
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
+
3
+# Copyright (c) 2013 Huawei Technologies Co., Ltd.
4
+# Copyright (c) 2012 OpenStack LLC.
5
+# All Rights Reserved.
6
+#
7
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
8
+#    not use this file except in compliance with the License. You may obtain
9
+#    a copy of the License at
10
+#
11
+#         http://www.apache.org/licenses/LICENSE-2.0
12
+#
13
+#    Unless required by applicable law or agreed to in writing, software
14
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16
+#    License for the specific language governing permissions and limitations
17
+#    under the License.
18
+
19
+from xml.etree import ElementTree as ET
20
+
21
+from cinder import exception
22
+from cinder.openstack.common import log as logging
23
+
24
+LOG = logging.getLogger(__name__)
25
+
26
+os_type = {'Linux': '0',
27
+           'Windows': '1',
28
+           'Solaris': '2',
29
+           'HP-UX': '3',
30
+           'AIX': '4',
31
+           'XenServer': '5',
32
+           'Mac OS X': '6',
33
+           'VMware ESX': '7'}
34
+
35
+
36
+def parse_xml_file(filepath):
37
+    """Get root of xml file."""
38
+    try:
39
+        tree = ET.parse(filepath)
40
+        root = tree.getroot()
41
+        return root
42
+    except IOError as err:
43
+        LOG.error(_('parse_xml_file: %s') % err)
44
+        raise err
45
+
46
+
47
+def get_xml_item(xml_root, item):
48
+    """Get the given item details.
49
+
50
+    :param xml_root: The root of xml tree
51
+    :param item: The tag need to get
52
+    :return: A dict contains all the config info of the given item.
53
+    """
54
+    items_list = []
55
+    items = xml_root.findall(item)
56
+    for item in items:
57
+        tmp_dict = {'text': None, 'attrib': {}}
58
+        if item.text:
59
+            tmp_dict['text'] = item.text.strip()
60
+        for key, val in item.attrib.items():
61
+            if val:
62
+                item.attrib[key] = val.strip()
63
+        tmp_dict['attrib'] = item.attrib
64
+        items_list.append(tmp_dict)
65
+    return items_list
66
+
67
+
68
+def is_xml_item_exist(xml_root, item, attrib_key=None):
69
+    """Check if the given item exits in xml config file.
70
+
71
+    :param xml_root: The root of xml tree
72
+    :param item: The xml tag to check
73
+    :param attrib_key: The xml attrib to check
74
+    :return: True of False
75
+    """
76
+    items_list = get_xml_item(xml_root, item)
77
+    value = []
78
+    if attrib_key:
79
+        for tmp_dict in items_list:
80
+            if tmp_dict['attrib'].get(attrib_key, None):
81
+                return True
82
+    else:
83
+        if items_list and items_list[0]['text']:
84
+            return True
85
+    return False
86
+
87
+
88
+def is_xml_item_valid(xml_root, item, valid_list, attrib_key=None):
89
+    """Check if the given item is valid in xml config file.
90
+
91
+    :param xml_root: The root of xml tree
92
+    :param item: The xml tag to check
93
+    :param valid_list: The valid item value
94
+    :param attrib_key: The xml attrib to check
95
+    :return: True of False
96
+    """
97
+    items_list = get_xml_item(xml_root, item)
98
+    if attrib_key:
99
+        for tmp_dict in items_list:
100
+            value = tmp_dict['attrib'].get(attrib_key, None)
101
+            if value not in valid_list:
102
+                return False
103
+    else:
104
+        value = items_list[0]['text']
105
+        if value not in valid_list:
106
+            return False
107
+
108
+    return True
109
+
110
+
111
+def get_conf_host_os_type(host_ip, config):
112
+    """Get host OS type from xml config file.
113
+
114
+    :param host_ip: The IP of Nova host
115
+    :param config: xml config file
116
+    :return: host OS type
117
+    """
118
+    os_conf = {}
119
+    root = parse_xml_file(config)
120
+    hosts_list = get_xml_item(root, 'Host')
121
+    for host in hosts_list:
122
+        os = host['attrib']['OSType'].strip()
123
+        ips = [ip.strip() for ip in host['attrib']['HostIP'].split(',')]
124
+        os_conf[os] = ips
125
+    host_os = None
126
+    for k, v in os_conf.items():
127
+        if host_ip in v:
128
+            host_os = os_type.get(k, None)
129
+    if not host_os:
130
+        host_os = os_type['Linux']  # default os type
131
+
132
+    LOG.debug(_('_get_host_os_type: Host %(ip)s OS type is %(os)s.')
133
+              % {'ip': host_ip, 'os': host_os})
134
+
135
+    return host_os

+ 45
- 40
cinder/volume/drivers/huawei/rest_common.py View File

@@ -32,6 +32,7 @@ from cinder.openstack.common import excutils
32 32
 from cinder.openstack.common import log as logging
33 33
 from cinder import units
34 34
 from cinder import utils
35
+from cinder.volume.drivers.huawei import huawei_utils
35 36
 from cinder.volume import volume_types
36 37
 
37 38
 
@@ -48,6 +49,7 @@ class HVSCommon():
48 49
         self.configuration = configuration
49 50
         self.cookie = cookielib.CookieJar()
50 51
         self.url = None
52
+        self.xml_conf = self.configuration.cinder_huawei_conf_file
51 53
 
52 54
     def call(self, url=False, data=None, method=None):
53 55
         """Send requests to HVS server.
@@ -170,9 +172,9 @@ class HVSCommon():
170 172
 
171 173
     def _assert_data_in_result(self, result, msg):
172 174
         if "data" not in result:
173
-            msg = _('%s "data" was not in result.') % msg
174
-            LOG.error(msg)
175
-            raise exception.CinderException(msg)
175
+            err_msg = _('%s "data" was not in result.') % msg
176
+            LOG.error(err_msg)
177
+            raise exception.CinderException(err_msg)
176 178
 
177 179
     def _create_volume(self, lun_param):
178 180
         url = self.url + "/lun"
@@ -266,17 +268,6 @@ class HVSCommon():
266 268
         result = self.call(url, data, "DELETE")
267 269
         self._assert_rest_result(result, 'delete lun error')
268 270
 
269
-    def _read_xml(self):
270
-        """Open xml file and parse the content."""
271
-        filename = self.configuration.cinder_huawei_conf_file
272
-        try:
273
-            tree = ET.parse(filename)
274
-            root = tree.getroot()
275
-        except Exception as err:
276
-            LOG.error(_('_read_xml:%s') % err)
277
-            raise err
278
-        return root
279
-
280 271
     def _encode_name(self, name):
281 272
         uuid_str = name.replace("-", "")
282 273
         vol_uuid = uuid.UUID('urn:uuid:%s' % uuid_str)
@@ -285,7 +276,7 @@ class HVSCommon():
285 276
         return newuuid
286 277
 
287 278
     def _find_pool_info(self):
288
-        root = self._read_xml()
279
+        root = huawei_utils.parse_xml_file(self.xml_conf)
289 280
         pool_name = root.findtext('LUN/StoragePool')
290 281
         if not pool_name:
291 282
             err_msg = _("Invalid resource pool: %s") % pool_name
@@ -455,7 +446,7 @@ class HVSCommon():
455 446
 
456 447
         return result['data']['ID']
457 448
 
458
-    def _add_host_into_hostgroup(self, host_name):
449
+    def _add_host_into_hostgroup(self, host_name, host_ip):
459 450
         """Associate host to hostgroup.
460 451
 
461 452
         If host group doesn't exist, create one.
@@ -468,7 +459,9 @@ class HVSCommon():
468 459
 
469 460
         hostid = self._find_host(host_name)
470 461
         if hostid is None:
471
-            hostid = self._add_host(host_name)
462
+            os_type = huawei_utils.get_conf_host_os_type(host_ip,
463
+                                                         self.xml_conf)
464
+            hostid = self._add_host(host_name, os_type)
472 465
             self._associate_host_to_hostgroup(hostgroup_id, hostid)
473 466
 
474 467
         return hostid, hostgroup_id
@@ -515,17 +508,18 @@ class HVSCommon():
515 508
     def initialize_connection_iscsi(self, volume, connector):
516 509
         """Map a volume to a host and return target iSCSI information."""
517 510
         initiator_name = connector['initiator']
518
-        host_name = connector['host']
519 511
         volume_name = self._encode_name(volume['id'])
520 512
 
521 513
         LOG.debug(_('initiator name:%(initiator_name)s, '
522 514
                     'volume name:%(volume)s.')
523 515
                   % {'initiator_name': initiator_name,
524 516
                      'volume': volume_name})
517
+
525 518
         (iscsi_iqn, target_ip) = self._get_iscsi_params(connector)
526 519
 
527 520
         #create host_goup if not exist
528
-        hostid, hostgroup_id = self._add_host_into_hostgroup(host_name)
521
+        hostid, hostgroup_id = self._add_host_into_hostgroup(connector['host'],
522
+                                                             connector['ip'])
529 523
         self._ensure_initiator_added(initiator_name, hostid)
530 524
 
531 525
         # Mapping lungooup and hostgoup to view
@@ -546,7 +540,6 @@ class HVSCommon():
546 540
 
547 541
     def initialize_connection_fc(self, volume, connector):
548 542
         wwns = connector['wwpns']
549
-        host_name = connector['host']
550 543
         volume_name = self._encode_name(volume['id'])
551 544
 
552 545
         LOG.debug(_('initiator name:%(initiator_name)s, '
@@ -554,8 +547,9 @@ class HVSCommon():
554 547
                   % {'initiator_name': wwns,
555 548
                      'volume': volume_name})
556 549
 
557
-        # Create host goup if not exist
558
-        hostid, hostgroup_id = self._add_host_into_hostgroup(host_name)
550
+        # Create host group if not exist
551
+        hostid, hostgroup_id = self._add_host_into_hostgroup(connector['host'],
552
+                                                             connector['ip'])
559 553
 
560 554
         free_wwns = self._get_connected_free_wwns()
561 555
         LOG.debug(_("the free wwns %s") % free_wwns)
@@ -713,12 +707,12 @@ class HVSCommon():
713 707
                     break
714 708
         return host_id
715 709
 
716
-    def _add_host(self, hostname):
710
+    def _add_host(self, hostname, type):
717 711
         """Add a new host."""
718 712
         url = self.url + "/host"
719 713
         data = json.dumps({"TYPE": "21",
720 714
                            "NAME": hostname,
721
-                           "OPERATIONSYSTEM": "0"})
715
+                           "OPERATIONSYSTEM": type})
722 716
         result = self.call(url, data)
723 717
         self._assert_rest_result(result, 'Add new host error.')
724 718
 
@@ -931,7 +925,7 @@ class HVSCommon():
931 925
                       'PrefetchValue': '0',
932 926
                       'PrefetchTimes': '0'}
933 927
 
934
-        root = self._read_xml()
928
+        root = huawei_utils.parse_xml_file(self.xml_conf)
935 929
         luntype = root.findtext('LUN/LUNType')
936 930
         if luntype:
937 931
             if luntype.strip() in ['Thick', 'Thin']:
@@ -1065,7 +1059,7 @@ class HVSCommon():
1065 1059
     def _get_iscsi_conf(self):
1066 1060
         """Get iSCSI info from config file."""
1067 1061
         iscsiinfo = {}
1068
-        root = self._read_xml()
1062
+        root = huawei_utils.parse_xml_file(self.xml_conf)
1069 1063
         iscsiinfo['DefaultTargetIP'] = \
1070 1064
             root.findtext('iSCSI/DefaultTargetIP').strip()
1071 1065
         initiator_list = []
@@ -1237,24 +1231,35 @@ class HVSCommon():
1237 1231
 
1238 1232
     def _check_conf_file(self):
1239 1233
         """Check the config file, make sure the essential items are set."""
1240
-        root = self._read_xml()
1241
-        hvsurl = root.findtext('Storage/HVSURL')
1242
-        username = root.findtext('Storage/UserName')
1243
-        pwd = root.findtext('Storage/UserPassword')
1244
-        pool_node = root.findall('LUN/StoragePool')
1245
-
1246
-        if (not hvsurl) or (not username) or (not pwd):
1247
-            err_msg = (_('_check_conf_file: Config file invalid. HVSURL,'
1248
-                         ' UserName and UserPassword must be set.'))
1249
-            LOG.error(err_msg)
1250
-            raise exception.InvalidInput(reason=err_msg)
1234
+        root = huawei_utils.parse_xml_file(self.xml_conf)
1235
+        check_list = ['Storage/HVSURL', 'Storage/UserName',
1236
+                      'Storage/UserPassword']
1237
+        for item in check_list:
1238
+            if not huawei_utils.is_xml_item_exist(root, item):
1239
+                err_msg = (_('_check_conf_file: Config file invalid. '
1240
+                             '%s must be set.') % item)
1241
+                LOG.error(err_msg)
1242
+                raise exception.InvalidInput(reason=err_msg)
1251 1243
 
1252
-        if not pool_node:
1253
-            err_msg = (_('_check_conf_file: Config file invalid. '
1254
-                         'StoragePool must be set.'))
1244
+        # make sure storage pool is set
1245
+        if not huawei_utils.is_xml_item_exist(root, 'LUN/StoragePool'):
1246
+            err_msg = _('_check_conf_file: Config file invalid. '
1247
+                        'StoragePool must be set.')
1255 1248
             LOG.error(err_msg)
1256 1249
             raise exception.InvalidInput(reason=err_msg)
1257 1250
 
1251
+        # make sure host os type valid
1252
+        if huawei_utils.is_xml_item_exist(root, 'Host', 'OSType'):
1253
+            os_list = huawei_utils.os_type.keys()
1254
+            if not huawei_utils.is_xml_item_valid(root, 'Host', os_list,
1255
+                                                  'OSType'):
1256
+                err_msg = (_('_check_conf_file: Config file invalid. '
1257
+                             'Host OSType invalid.\n'
1258
+                             'The valid values are: %(os_list)s')
1259
+                           % {'os_list': os_list})
1260
+                LOG.error(err_msg)
1261
+                raise exception.InvalidInput(reason=err_msg)
1262
+
1258 1263
     def _get_iscsi_params(self, connector):
1259 1264
         """Get target iSCSI params, including iqn, IP."""
1260 1265
         initiator = connector['initiator']

+ 61
- 50
cinder/volume/drivers/huawei/ssh_common.py View File

@@ -34,6 +34,7 @@ from cinder import exception
34 34
 from cinder.openstack.common import excutils
35 35
 from cinder.openstack.common import log as logging
36 36
 from cinder import utils
37
+from cinder.volume.drivers.huawei import huawei_utils
37 38
 from cinder.volume import volume_types
38 39
 
39 40
 
@@ -44,17 +45,6 @@ HOST_NAME_PREFIX = 'Host_'
44 45
 VOL_AND_SNAP_NAME_PREFIX = 'OpenStack_'
45 46
 
46 47
 
47
-def parse_xml_file(filepath):
48
-    """Get root of xml file."""
49
-    try:
50
-        tree = ET.parse(filepath)
51
-        root = tree.getroot()
52
-        return root
53
-    except IOError as err:
54
-        LOG.error(_('parse_xml_file: %s') % err)
55
-        raise err
56
-
57
-
58 48
 def ssh_read(user, channel, cmd, timeout):
59 49
     """Get results of CLI commands."""
60 50
     result = ''
@@ -105,7 +95,7 @@ class TseriesCommon():
105 95
         self.hostgroup_id = None
106 96
         self.ssh_pool = None
107 97
         self.lock_ip = threading.Lock()
108
-        self.luncopy_list = []  # to storage LUNCopy name
98
+        self.luncopy_list = []  # to store LUNCopy name
109 99
 
110 100
     def do_setup(self, context):
111 101
         """Check config file."""
@@ -119,27 +109,34 @@ class TseriesCommon():
119 109
 
120 110
     def _check_conf_file(self):
121 111
         """Check config file, make sure essential items are set."""
122
-        root = parse_xml_file(self.xml_conf)
123
-        IP1 = root.findtext('Storage/ControllerIP0')
124
-        IP2 = root.findtext('Storage/ControllerIP1')
125
-        username = root.findtext('Storage/UserName')
126
-        pwd = root.findtext('Storage/UserPassword')
127
-        pool_node = root.findall('LUN/StoragePool')
128
-
129
-        if (not IP1 or not IP2) or (not username) or (not pwd):
130
-            err_msg = (_('_check_conf_file: Config file invalid. Controler IP,'
131
-                         ' UserName and UserPassword must be set.'))
112
+        root = huawei_utils.parse_xml_file(self.xml_conf)
113
+        check_list = ['Storage/ControllerIP0', 'Storage/ControllerIP1',
114
+                      'Storage/UserName', 'Storage/UserPassword']
115
+        for item in check_list:
116
+            if not huawei_utils.is_xml_item_exist(root, item):
117
+                err_msg = (_('_check_conf_file: Config file invalid. '
118
+                             '%s must be set.') % item)
119
+                LOG.error(err_msg)
120
+                raise exception.InvalidInput(reason=err_msg)
121
+
122
+        # make sure storage pool is set
123
+        if not huawei_utils.is_xml_item_exist(root, 'LUN/StoragePool', 'Name'):
124
+            err_msg = _('_check_conf_file: Config file invalid. '
125
+                        'StoragePool must be set.')
132 126
             LOG.error(err_msg)
133 127
             raise exception.InvalidInput(reason=err_msg)
134 128
 
135
-        for pool in pool_node:
136
-            if pool.attrib['Name']:
137
-                return
138
-        # If pool_node is None or pool.attrib['Name'] is None.
139
-        err_msg = (_('_check_conf_file: Config file invalid. '
140
-                     'StoragePool must be set.'))
141
-        LOG.error(err_msg)
142
-        raise exception.InvalidInput(reason=err_msg)
129
+        # If setting os type, make sure it valid
130
+        if huawei_utils.is_xml_item_exist(root, 'Host', 'OSType'):
131
+            os_list = huawei_utils.os_type.keys()
132
+            if not huawei_utils.is_xml_item_valid(root, 'Host', os_list,
133
+                                                  'OSType'):
134
+                err_msg = (_('_check_conf_file: Config file invalid. '
135
+                             'Host OSType is invalid.\n'
136
+                             'The valid values are: %(os_list)s')
137
+                           % {'os_list': os_list})
138
+                LOG.error(err_msg)
139
+                raise exception.InvalidInput(reason=err_msg)
143 140
 
144 141
     def _get_login_info(self):
145 142
         """Get login IP, username and password from config file."""
@@ -356,7 +353,7 @@ class TseriesCommon():
356 353
                        'PrefetchTimes': '0',
357 354
                        'StoragePool': []}
358 355
 
359
-        root = parse_xml_file(self.xml_conf)
356
+        root = huawei_utils.parse_xml_file(self.xml_conf)
360 357
 
361 358
         luntype = root.findtext('LUN/LUNType')
362 359
         if luntype:
@@ -405,7 +402,7 @@ class TseriesCommon():
405 402
         maxpool_id = None
406 403
         maxpool_size = 0.0
407 404
         nameindex, sizeindex = ((1, 4) if luntype == 'Thin' else (5, 3))
408
-        pools_dev = sorted(pools_dev, key=lambda x: int(x[sizeindex]))
405
+        pools_dev = sorted(pools_dev, key=lambda x: float(x[sizeindex]))
409 406
         while len(pools_dev) > 0:
410 407
             pool = pools_dev.pop()
411 408
             if pool[nameindex] in pools_conf:
@@ -892,7 +889,7 @@ class TseriesCommon():
892 889
 
893 890
         return hostlun_id
894 891
 
895
-    def add_host(self, host_name, initiator=None):
892
+    def add_host(self, host_name, host_ip, initiator=None):
896 893
         """Create a host and add it to hostgroup."""
897 894
         # Create an OpenStack hostgroup if not created before.
898 895
         hostgroup_name = HOST_GROUP_NAME
@@ -913,7 +910,9 @@ class TseriesCommon():
913 910
         host_name = HOST_NAME_PREFIX + host_name
914 911
         host_id = self._get_host_id(host_name, self.hostgroup_id)
915 912
         if host_id is None:
916
-            self._create_host(host_name, self.hostgroup_id)
913
+            os_type = huawei_utils.get_conf_host_os_type(host_ip,
914
+                                                         self.xml_conf)
915
+            self._create_host(host_name, self.hostgroup_id, os_type)
917 916
             host_id = self._get_host_id(host_name, self.hostgroup_id)
918 917
 
919 918
         return host_id
@@ -955,11 +954,12 @@ class TseriesCommon():
955 954
                     return tmp_line[0]
956 955
         return None
957 956
 
958
-    def _create_host(self, hostname, hostgroupid):
957
+    def _create_host(self, hostname, hostgroupid, type):
959 958
         """Run CLI command to add host."""
960
-        cli_cmd = ('addhost -group %(groupid)s -n %(hostname)s -t 0'
959
+        cli_cmd = ('addhost -group %(groupid)s -n %(hostname)s -t %(type)s'
961 960
                    % {'groupid': hostgroupid,
962
-                      'hostname': hostname})
961
+                      'hostname': hostname,
962
+                      'type': type})
963 963
         out = self._execute_cli(cli_cmd)
964 964
 
965 965
         self._assert_cli_operate_out('_create_host',
@@ -1178,30 +1178,41 @@ class DoradoCommon(TseriesCommon):
1178 1178
 
1179 1179
     def _check_conf_file(self):
1180 1180
         """Check the config file, make sure the key elements are set."""
1181
-        root = parse_xml_file(self.xml_conf)
1181
+        root = huawei_utils.parse_xml_file(self.xml_conf)
1182 1182
         # Check login infomation
1183
-        IP1 = root.findtext('Storage/ControllerIP0')
1184
-        IP2 = root.findtext('Storage/ControllerIP1')
1185
-        username = root.findtext('Storage/UserName')
1186
-        pwd = root.findtext('Storage/UserPassword')
1187
-        if (not IP1 and not IP2) or (not username) or (not pwd):
1188
-            err_msg = (_('Config file invalid. Controler IP, UserName, '
1189
-                         'UserPassword must be specified.'))
1190
-            LOG.error(err_msg)
1191
-            raise exception.InvalidInput(reason=err_msg)
1183
+        check_list = ['Storage/ControllerIP0', 'Storage/ControllerIP1',
1184
+                      'Storage/UserName', 'Storage/UserPassword']
1185
+        for item in check_list:
1186
+            if not huawei_utils.is_xml_item_exist(root, item):
1187
+                err_msg = (_('_check_conf_file: Config file invalid. '
1188
+                             '%s must be set.') % item)
1189
+                LOG.error(err_msg)
1190
+                raise exception.InvalidInput(reason=err_msg)
1192 1191
 
1193 1192
         # Check storage pool
1194 1193
         # No need for Dorado2100 G2
1195 1194
         self.login_info = self._get_login_info()
1196 1195
         self.device_type = self._get_device_type()
1197 1196
         if self.device_type == 'Dorado5100':
1198
-            pool_node = root.findall('LUN/StoragePool')
1199
-            if not pool_node:
1197
+            if not huawei_utils.is_xml_item_exist(root, 'LUN/StoragePool',
1198
+                                                  'Name'):
1200 1199
                 err_msg = (_('_check_conf_file: Config file invalid. '
1201 1200
                              'StoragePool must be specified.'))
1202 1201
                 LOG.error(err_msg)
1203 1202
                 raise exception.InvalidInput(reason=err_msg)
1204 1203
 
1204
+        # If setting os type, make sure it valid
1205
+        if huawei_utils.is_xml_item_exist(root, 'Host', 'OSType'):
1206
+            os_list = huawei_utils.os_type.keys()
1207
+            if not huawei_utils.is_xml_item_valid(root, 'Host', os_list,
1208
+                                                  'OSType'):
1209
+                err_msg = (_('_check_conf_file: Config file invalid. '
1210
+                             'Host OSType is invalid.\n'
1211
+                             'The valid values are: %(os_list)s')
1212
+                           % {'os_list': os_list})
1213
+                LOG.error(err_msg)
1214
+                raise exception.InvalidInput(reason=err_msg)
1215
+
1205 1216
     def _get_device_type(self):
1206 1217
         """Run CLI command to get system type."""
1207 1218
         cli_cmd = 'showsys'
@@ -1333,7 +1344,7 @@ class DoradoCommon(TseriesCommon):
1333 1344
                        'WriteType': '1',
1334 1345
                        'MirrorSwitch': '1'}
1335 1346
 
1336
-        root = parse_xml_file(self.xml_conf)
1347
+        root = huawei_utils.parse_xml_file(self.xml_conf)
1337 1348
 
1338 1349
         luntype = root.findtext('LUN/LUNType')
1339 1350
         if luntype:

Loading…
Cancel
Save