diff --git a/dracclient/resources/inventory.py b/dracclient/resources/inventory.py index 0de7564..bd17b80 100644 --- a/dracclient/resources/inventory.py +++ b/dracclient/resources/inventory.py @@ -101,15 +101,17 @@ class InventoryManagement(object): speed_mhz=int(self._get_cpu_attr(cpu, 'CurrentClockSpeed')), model=self._get_cpu_attr(cpu, 'Model'), status=PRIMARY_STATUS[self._get_cpu_attr(cpu, 'PrimaryStatus')], - ht_enabled=bool(self._get_cpu_attr(cpu, 'HyperThreadingEnabled')), - turbo_enabled=bool(self._get_cpu_attr(cpu, 'TurboModeEnabled')), - vt_enabled=bool(self._get_cpu_attr(cpu, - 'VirtualizationTechnologyEnabled')), + ht_enabled=bool(self._get_cpu_attr(cpu, 'HyperThreadingEnabled', + allow_missing=True)), + turbo_enabled=bool(self._get_cpu_attr(cpu, 'TurboModeEnabled', + allow_missing=True)), + vt_enabled=bool(self._get_cpu_attr( + cpu, 'VirtualizationTechnologyEnabled', allow_missing=True)), arch64=arch64) - def _get_cpu_attr(self, cpu, attr_name): + def _get_cpu_attr(self, cpu, attr_name, allow_missing=False): return utils.get_wsman_resource_attr( - cpu, uris.DCIM_CPUView, attr_name) + cpu, uris.DCIM_CPUView, attr_name, allow_missing=allow_missing) def list_memory(self): """Returns the list of installed memory diff --git a/dracclient/tests/test_client.py b/dracclient/tests/test_client.py index 80f815c..1197745 100644 --- a/dracclient/tests/test_client.py +++ b/dracclient/tests/test_client.py @@ -1074,6 +1074,27 @@ class ClientInventoryManagementTestCase(base.BaseTest): expected_cpu, self.drac_client.list_cpus()) + def test_list_cpus_with_missing_flags(self, mock_requests): + expected_cpu = [inventory.CPU( + id='CPU.Socket.1', + cores=8, + speed_mhz=1900, + model='Intel(R) Xeon(R) CPU E5-2440 v2 @ 1.90GHz', + status='OK', + ht_enabled=False, + turbo_enabled=False, + vt_enabled=False, + arch64=False)] + + mock_requests.post( + 'https://1.2.3.4:443/wsman', + text=test_utils.InventoryEnumerations[ + uris.DCIM_CPUView]['missing_flags']) + + self.assertEqual( + expected_cpu, + self.drac_client.list_cpus()) + def test_list_memory(self, mock_requests): expected_memory = [inventory.Memory( id='DIMM.Socket.A1', diff --git a/dracclient/tests/test_utils.py b/dracclient/tests/test_utils.py new file mode 100644 index 0000000..e31df2c --- /dev/null +++ b/dracclient/tests/test_utils.py @@ -0,0 +1,65 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import re + +from lxml import etree + +from dracclient.resources import uris +from dracclient.tests import base +from dracclient.tests import utils as test_utils +from dracclient import utils + + +class UtilsTestCase(base.BaseTest): + + def setUp(self): + super(UtilsTestCase, self).setUp() + + def test_get_wsman_resource_attr(self): + doc = etree.fromstring( + test_utils.InventoryEnumerations[uris.DCIM_CPUView]['ok']) + cpus = utils.find_xml(doc, 'DCIM_CPUView', uris.DCIM_CPUView, + find_all=True) + + val = utils.get_wsman_resource_attr( + cpus[0], uris.DCIM_CPUView, 'HyperThreadingEnabled', + allow_missing=False) + + self.assertEqual('1', val) + + def test_get_wsman_resource_attr_missing_attr(self): + expected_message = ("Could not find attribute 'HyperThreadingEnabled'") + doc = etree.fromstring( + test_utils.InventoryEnumerations[ + uris.DCIM_CPUView]['missing_flags']) + cpus = utils.find_xml(doc, 'DCIM_CPUView', uris.DCIM_CPUView, + find_all=True) + + self.assertRaisesRegexp( + AttributeError, re.escape(expected_message), + utils.get_wsman_resource_attr, cpus[0], uris.DCIM_CPUView, + 'HyperThreadingEnabled', allow_missing=False) + + def test_get_wsman_resource_attr_missing_attr_allowed(self): + doc = etree.fromstring( + test_utils.InventoryEnumerations[ + uris.DCIM_CPUView]['missing_flags']) + cpus = utils.find_xml(doc, 'DCIM_CPUView', uris.DCIM_CPUView, + find_all=True) + + val = utils.get_wsman_resource_attr( + cpus[0], uris.DCIM_CPUView, 'HyperThreadingEnabled', + allow_missing=True) + + self.assertIsNone(val) diff --git a/dracclient/tests/utils.py b/dracclient/tests/utils.py index 7310765..3dc8a77 100644 --- a/dracclient/tests/utils.py +++ b/dracclient/tests/utils.py @@ -99,10 +99,11 @@ BIOSInvocations = { InventoryEnumerations = { uris.DCIM_CPUView: { - 'ok': load_wsman_xml('cpu-enumeration-enum-ok') + 'ok': load_wsman_xml('cpu_view-enum-ok'), + 'missing_flags': load_wsman_xml('cpu_view-enum-missing_flags') }, uris.DCIM_MemoryView: { - 'ok': load_wsman_xml('memory-enumeration-enum-ok') + 'ok': load_wsman_xml('memory_view-enum-ok') }, uris.DCIM_NICView: { 'ok': load_wsman_xml('nic_view-enum-ok') diff --git a/dracclient/tests/wsman_mocks/cpu_view-enum-missing_flags.xml b/dracclient/tests/wsman_mocks/cpu_view-enum-missing_flags.xml new file mode 100644 index 0000000..d955f64 --- /dev/null +++ b/dracclient/tests/wsman_mocks/cpu_view-enum-missing_flags.xml @@ -0,0 +1,64 @@ + + + http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous + http://schemas.xmlsoap.org/ws/2004/09/enumeration/EnumerateResponse + uuid:bde5656e-1253-4545-87dd-a111346efebe + uuid:35d42397-376d-176d-8062-a36fc6fe83b0 + + + + + + B3 + 1 + 7 + 5 + 0 + 1 + 2 + 256 + 4 + 1 + 7 + 5 + 1 + 1 + 2 + 2048 + 5 + 1 + 14 + 5 + 2 + 1 + 2 + 20480 + 5 + 1 + 2 + 1900 + CPU 1 + 6400 + CPU.Socket.1 + CPU.Socket.1 + 20160706154809.000000+000 + 20141016232016.000000+000 + Intel + 3600 + Intel(R) Xeon(R) CPU E5-2440 v2 @ 1.90GHz + 8 + 16 + 8 + 1 + 1.2 + + + + + + + \ No newline at end of file diff --git a/dracclient/tests/wsman_mocks/cpu-enumeration-enum-ok.xml b/dracclient/tests/wsman_mocks/cpu_view-enum-ok.xml similarity index 100% rename from dracclient/tests/wsman_mocks/cpu-enumeration-enum-ok.xml rename to dracclient/tests/wsman_mocks/cpu_view-enum-ok.xml diff --git a/dracclient/tests/wsman_mocks/memory-enumeration-enum-ok.xml b/dracclient/tests/wsman_mocks/memory_view-enum-ok.xml similarity index 100% rename from dracclient/tests/wsman_mocks/memory-enumeration-enum-ok.xml rename to dracclient/tests/wsman_mocks/memory_view-enum-ok.xml diff --git a/dracclient/utils.py b/dracclient/utils.py index 4d2b181..61f9116 100644 --- a/dracclient/utils.py +++ b/dracclient/utils.py @@ -44,7 +44,8 @@ def find_xml(doc, item, namespace, find_all=False): return doc.find(query) -def get_wsman_resource_attr(doc, resource_uri, attr_name, nullable=False): +def get_wsman_resource_attr(doc, resource_uri, attr_name, nullable=False, + allow_missing=False): """Find an attribute of a resource in an ElementTree object. :param doc: the element tree object. @@ -53,10 +54,21 @@ def get_wsman_resource_attr(doc, resource_uri, attr_name, nullable=False): :param nullable: enables checking if the element contains an XMLSchema-instance namespaced nil attribute that has a value of True. In this case, it will return None. + :param allow_missing: if set to True, attributes missing from the XML + document will return None instead of raising + AttributeError. + :raises: AttributeError if the attribute is missing from the XML doc and + allow_missing is False. :returns: value of the attribute """ item = find_xml(doc, attr_name, resource_uri) + if item is None: + if allow_missing: + return + else: + raise AttributeError("Could not find attribute '%s'" % (attr_name)) + if not nullable: return item.text.strip() else: