From 3823a53040ef10f0e807e9a29a637b52cac299ab Mon Sep 17 00:00:00 2001
From: Yuiko Takada <takada-yuiko@mxn.nes.nec.co.jp>
Date: Mon, 1 Feb 2016 17:18:30 +0900
Subject: [PATCH] Add 'system_vendor' information to data

This patch set add hardware vendor information to data.
By using this data, we can get hints to detect driver.

Change-Id: I39385fd5d616edfad719c255f22642f215bfb532
---
 ironic_python_agent/hardware.py               | 34 ++++++++++++++++++
 .../tests/unit/test_hardware.py               | 35 +++++++++++++++++++
 .../add-vendor-info-56be9a8605d80bf0.yaml     |  5 +++
 3 files changed, 74 insertions(+)
 create mode 100644 releasenotes/notes/add-vendor-info-56be9a8605d80bf0.yaml

diff --git a/ironic_python_agent/hardware.py b/ironic_python_agent/hardware.py
index 3f0f0771e..3032a8019 100644
--- a/ironic_python_agent/hardware.py
+++ b/ironic_python_agent/hardware.py
@@ -188,6 +188,15 @@ class Memory(encoding.SerializableComparable):
         self.physical_mb = physical_mb
 
 
+class SystemVendorInfo(encoding.SerializableComparable):
+    serializable_fields = ('product_name', 'serial_number', 'manufacturer')
+
+    def __init__(self, product_name, serial_number, manufacturer):
+        self.product_name = product_name
+        self.serial_number = serial_number
+        self.manufacturer = manufacturer
+
+
 @six.add_metaclass(abc.ABCMeta)
 class HardwareManager(object):
     @abc.abstractmethod
@@ -264,6 +273,7 @@ class HardwareManager(object):
         hardware_info['disks'] = self.list_block_devices()
         hardware_info['memory'] = self.get_memory()
         hardware_info['bmc_address'] = self.get_bmc_address()
+        hardware_info['system_vendor'] = self.get_system_vendor_info()
         return hardware_info
 
     def get_clean_steps(self, node, ports):
@@ -492,6 +502,30 @@ class GenericHardwareManager(HardwareManager):
                     "No suitable device was found for "
                     "deployment using these hints %s" % root_device_hints)
 
+    def get_system_vendor_info(self):
+        product_name = None
+        serial_number = None
+        manufacturer = None
+        try:
+            out, _e = utils.execute("dmidecode --type system",
+                                    shell=True)
+        except (processutils.ProcessExecutionError, OSError) as e:
+            LOG.warning("Cannot get system vendor information: %s", e)
+        else:
+            for line in out.split('\n'):
+                line_arr = line.split(':', 1)
+                if len(line_arr) != 2:
+                    continue
+                if line_arr[0].strip() == 'Product Name':
+                    product_name = line_arr[1].strip()
+                elif line_arr[0].strip() == 'Serial Number':
+                    serial_number = line_arr[1].strip()
+                elif line_arr[0].strip() == 'Manufacturer':
+                    manufacturer = line_arr[1].strip()
+        return SystemVendorInfo(product_name=product_name,
+                                serial_number=serial_number,
+                                manufacturer=manufacturer)
+
     def erase_block_device(self, node, block_device):
 
         # Check if the block device is virtual media and skip the device.
diff --git a/ironic_python_agent/tests/unit/test_hardware.py b/ironic_python_agent/tests/unit/test_hardware.py
index 81b180fc9..fdee90ca3 100644
--- a/ironic_python_agent/tests/unit/test_hardware.py
+++ b/ironic_python_agent/tests/unit/test_hardware.py
@@ -834,6 +834,41 @@ class TestGenericHardwareManager(test_base.BaseTestCase):
         mocked_execute.side_effect = processutils.ProcessExecutionError()
         self.assertIsNone(self.hardware.get_bmc_address())
 
+    @mock.patch.object(utils, 'execute')
+    def test_get_system_vendor_info(self, mocked_execute):
+        mocked_execute.return_value = (
+            '# dmidecode 2.12\n'
+            'SMBIOS 2.6 present.\n'
+            '\n'
+            'Handle 0x0001, DMI type 1, 27 bytes\n'
+            'System Information\n'
+            '\tManufacturer: NEC\n'
+            '\tProduct Name: Express5800/R120b-2 [N8100-1653]\n'
+            '\tVersion: FR1.3\n'
+            '\tSerial Number: 0800113\n'
+            '\tUUID: 00433468-26A5-DF11-8001-406186F5A681\n'
+            '\tWake-up Type: Power Switch\n'
+            '\tSKU Number: Not Specified\n'
+            '\tFamily: Not Specified\n'
+            '\n'
+            'Handle 0x002E, DMI type 12, 5 bytes\n'
+            'System Configuration Options\n'
+            '\tOption 1: CLR_CMOS: Close to clear CMOS\n'
+            '\tOption 2: BMC_FRB3: Close to stop FRB3 Timer\n'
+            '\tOption 3: BIOS_RECOVERY: Close to run BIOS Recovery\n'
+            '\tOption 4: PASS_DIS: Close to clear Password\n'
+            '\n'
+            'Handle 0x0059, DMI type 32, 11 bytes\n'
+            'System Boot Information\n'
+            '\tStatus: No errors detected\n'
+        ), ''
+        self.assertEqual('Express5800/R120b-2 [N8100-1653]',
+                         self.hardware.get_system_vendor_info().product_name)
+        self.assertEqual('0800113',
+                         self.hardware.get_system_vendor_info().serial_number)
+        self.assertEqual('NEC',
+                         self.hardware.get_system_vendor_info().manufacturer)
+
 
 class TestModuleFunctions(test_base.BaseTestCase):
 
diff --git a/releasenotes/notes/add-vendor-info-56be9a8605d80bf0.yaml b/releasenotes/notes/add-vendor-info-56be9a8605d80bf0.yaml
new file mode 100644
index 000000000..0d32a9648
--- /dev/null
+++ b/releasenotes/notes/add-vendor-info-56be9a8605d80bf0.yaml
@@ -0,0 +1,5 @@
+---
+features:
+  - Add new 'system_vendor' information to data - Add hardware vendor
+    information(product name, serial number, manufacturer) to data.
+    This will be able to give Ironic Inspector hints to detect driver.