From 3152dd98e23c2e45dec04d1262813c8a50bb0e0e Mon Sep 17 00:00:00 2001
From: Sahid Orentino Ferdjaoui <sahid.ferdjaoui@redhat.com>
Date: Tue, 25 Apr 2017 08:04:26 -0400
Subject: [PATCH 10/10] libvirt: update the logic to configure volume with scsi
 controller

This commit is fixing the issue by adding the address element to the
volumes configuration.

 Conflicts:
	nova/virt/libvirt/driver.py

Closes-Bug: #1686116
Change-Id: I701145abc0e300711a01889e8d62b1f7887da120
(cherry picked from commit c25629f85feb53b5be0347f68c43b3b55fb9f137)
(cherry picked from commit be0f76ae6429e8d83fd99bd6c9365dfcd4702f42)
---
 nova/tests/unit/virt/libvirt/test_driver.py |  5 ++++-
 nova/virt/libvirt/driver.py                 | 17 +++++++++++++++++
 nova/virt/libvirt/volume/volume.py          | 11 +++++++++++
 3 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py
index 7fe8779e8f..f9cd41c158 100644
--- a/nova/tests/unit/virt/libvirt/test_driver.py
+++ b/nova/tests/unit/virt/libvirt/test_driver.py
@@ -3415,7 +3415,8 @@ class LibvirtConnTestCase(test.NoDBTestCase):
 
         image_meta = objects.ImageMeta.from_dict({
             "disk_format": "raw",
-            "properties": {"hw_scsi_model": "virtio-scsi"}})
+            "properties": {"hw_scsi_model": "virtio-scsi",
+                           "hw_disk_bus": "scsi"}})
         instance_ref = objects.Instance(**self.test_instance)
         conn_info = {'driver_volume_type': 'fake'}
         bdms = block_device_obj.block_device_make_list_from_dicts(
@@ -3448,10 +3449,12 @@ class LibvirtConnTestCase(test.NoDBTestCase):
                              vconfig.LibvirtConfigGuestDisk)
             self.assertEqual(cfg.devices[2].target_dev, 'sdc')
             self.assertEqual(cfg.devices[2].target_bus, 'scsi')
+            self.assertEqual(2, cfg.devices[2].device_addr.unit)
             self.assertIsInstance(cfg.devices[3],
                              vconfig.LibvirtConfigGuestDisk)
             self.assertEqual(cfg.devices[3].target_dev, 'sdd')
             self.assertEqual(cfg.devices[3].target_bus, 'scsi')
+            self.assertEqual(3, cfg.devices[3].device_addr.unit)
             self.assertIsInstance(cfg.devices[4],
                              vconfig.LibvirtConfigGuestController)
             self.assertEqual(cfg.devices[4].model, 'virtio-scsi')
diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py
index 3268dd29a3..a65fabebac 100644
--- a/nova/virt/libvirt/driver.py
+++ b/nova/virt/libvirt/driver.py
@@ -1005,6 +1005,17 @@ class LibvirtDriver(driver.ComputeDriver):
         for source in tcp_devices:
             yield (source.get("host"), int(source.get("service")))
 
+    def _get_scsi_controller_max_unit(self, guest):
+        """Returns the max disk unit used by scsi controller"""
+        xml = guest.get_xml_desc()
+        tree = etree.fromstring(xml)
+        addrs = "./devices/disk[@device='disk']/address[@type='drive']"
+
+        ret = []
+        for obj in tree.findall(addrs):
+            ret.append(int(obj.get('unit', 0)))
+        return max(ret)
+
     @staticmethod
     def _get_rbd_driver():
         return rbd_utils.RBDDriver(
@@ -1159,6 +1170,9 @@ class LibvirtDriver(driver.ComputeDriver):
         disk_info = blockinfo.get_info_from_bdm(
             instance, CONF.libvirt.virt_type, instance.image_meta, bdm)
         self._connect_volume(connection_info, disk_info)
+        if disk_info['bus'] == 'scsi':
+            disk_info['unit'] = self._get_scsi_controller_max_unit(guest) + 1
+
         conf = self._get_volume_config(connection_info, disk_info)
 
         self._check_discard_for_attach_volume(conf, instance)
@@ -3608,6 +3622,9 @@ class LibvirtDriver(driver.ComputeDriver):
             vol_dev = block_device.prepend_dev(vol['mount_device'])
             info = disk_mapping[vol_dev]
             self._connect_volume(connection_info, info)
+            if scsi_controller and scsi_controller.model == 'virtio-scsi':
+                info['unit'] = disk_mapping['unit']
+                disk_mapping['unit'] += 1
             cfg = self._get_volume_config(connection_info, info)
             devices.append(cfg)
             vol['connection_info'] = connection_info
diff --git a/nova/virt/libvirt/volume/volume.py b/nova/virt/libvirt/volume/volume.py
index 2efc0f5e06..f17e0c7304 100644
--- a/nova/virt/libvirt/volume/volume.py
+++ b/nova/virt/libvirt/volume/volume.py
@@ -112,6 +112,17 @@ class LibvirtBaseVolumeDriver(object):
                         'type': connection_info['driver_volume_type']
                     })
 
+        if disk_info['bus'] == 'scsi':
+            # The driver is responsible to create the SCSI controller
+            # at index 0.
+            conf.device_addr = vconfig.LibvirtConfigGuestDeviceAddressDrive()
+            conf.device_addr.controller = 0
+            if 'unit' in disk_info:
+                # In order to allow up to 256 disks handled by one
+                # virtio-scsi controller, the device addr should be
+                # specified.
+                conf.device_addr.unit = disk_info['unit']
+
         return conf
 
     def connect_volume(self, connection_info, disk_info):
-- 
2.13.7

