From 927367cd9af6adf260bea4da4dcc5cc94eaa7b13 Mon Sep 17 00:00:00 2001
From: John Cates <jccates@us.ibm.com>
Date: Wed, 11 Oct 2017 16:58:50 -0500
Subject: [PATCH] FlashSystems: permit snapshot/clone volumes larger than
 source

Permit clone volumes and volumes created from snapshots to
be larger than their source volumes; implemented in response
to failures in the following CI tests:
  * VolumesSnapshotTestJSON.test_volume_from_snapshot
  * VolumesCloneTest.test_create_from_volume

Change-Id: I21511e5c4db62563c61815c1671e8bb44ad3f427
Closes-Bug: #1560655
---
 .../drivers/ibm/test_ibm_flashsystem.py       |  7 ++-
 .../volume/drivers/ibm/flashsystem_common.py  | 53 +++++++++++--------
 2 files changed, 36 insertions(+), 24 deletions(-)

diff --git a/cinder/tests/unit/volume/drivers/ibm/test_ibm_flashsystem.py b/cinder/tests/unit/volume/drivers/ibm/test_ibm_flashsystem.py
index 63bec428f27..c27727a83e5 100644
--- a/cinder/tests/unit/volume/drivers/ibm/test_ibm_flashsystem.py
+++ b/cinder/tests/unit/volume/drivers/ibm/test_ibm_flashsystem.py
@@ -1028,12 +1028,15 @@ class FlashSystemDriverTestCase(test.TestCase):
         vol2 = self._generate_vol_info(None)
         self.driver.create_cloned_volume(vol2, vol1)
 
-        # case 2: when size does not match
+        # case 2: destination larger than source
         vol1 = self._generate_vol_info(None, vol_size=10)
         vol2 = self._generate_vol_info(None, vol_size=20)
+        self.driver.create_cloned_volume(vol2, vol1)
+
+        # case 3: destination smaller than source
         self.assertRaises(exception.VolumeDriverException,
                           self.driver.create_cloned_volume,
-                          vol2, vol1)
+                          vol1, vol2)
 
     def test_flashsystem_get_volume_stats(self):
         # case 1: good path
diff --git a/cinder/volume/drivers/ibm/flashsystem_common.py b/cinder/volume/drivers/ibm/flashsystem_common.py
index c37d4d4f53b..13607fcaa81 100644
--- a/cinder/volume/drivers/ibm/flashsystem_common.py
+++ b/cinder/volume/drivers/ibm/flashsystem_common.py
@@ -264,14 +264,17 @@ class FlashSystemDriver(san.SanDriver,
             {'src': src_vdisk_name, 'dest': dest_vdisk_name})
 
     def _create_and_copy_vdisk_data(self, src_vdisk_name, src_vdisk_id,
-                                    dest_vdisk_name, dest_vdisk_id):
-        vdisk_attr = self._get_vdisk_attributes(src_vdisk_name)
-        self._driver_assert(
-            vdisk_attr is not None,
-            (_('_create_and_copy_vdisk_data: Failed to get attributes for '
-               'vdisk %s.') % src_vdisk_name))
+                                    dest_vdisk_name, dest_vdisk_id,
+                                    dest_vdisk_size=None):
+        if dest_vdisk_size is None:
+            vdisk_attr = self._get_vdisk_attributes(src_vdisk_name)
+            self._driver_assert(
+                vdisk_attr is not None,
+                (_('_create_and_copy_vdisk_data: Failed to get attributes for '
+                   'vdisk %s.') % src_vdisk_name))
+            dest_vdisk_size = vdisk_attr['capacity']
 
-        self._create_vdisk(dest_vdisk_name, vdisk_attr['capacity'], 'b', None)
+        self._create_vdisk(dest_vdisk_name, dest_vdisk_size, 'b', None)
 
         # create a timer to lock vdisk that will be used to data copy
         timer = loopingcall.FixedIntervalLoopingCall(
@@ -297,7 +300,7 @@ class FlashSystemDriver(san.SanDriver,
         ssh_cmd = ['svctask', 'mkvdisk', '-name', name, '-mdiskgrp',
                    FLASHSYSTEM_VOLPOOL_NAME, '-iogrp',
                    six.text_type(FLASHSYSTEM_VOL_IOGRP),
-                   '-size', size, '-unit', unit]
+                   '-size', six.text_type(size), '-unit', unit]
         out, err = self._ssh(ssh_cmd)
         self._assert_ssh_return(out.strip(), '_create_vdisk',
                                 ssh_cmd, out, err)
@@ -1101,9 +1104,9 @@ class FlashSystemDriver(san.SanDriver,
             'enter: create_volume_from_snapshot: create %(vol)s from '
             '%(snap)s.', {'vol': volume['name'], 'snap': snapshot['name']})
 
-        if volume['size'] != snapshot['volume_size']:
-            msg = _('create_volume_from_snapshot: Volume size is different '
-                    'from snapshot based volume.')
+        if volume['size'] < snapshot['volume_size']:
+            msg = _('create_volume_from_snapshot: Volume is smaller than '
+                    'snapshot.')
             LOG.error(msg)
             raise exception.VolumeDriverException(message=msg)
 
@@ -1114,10 +1117,13 @@ class FlashSystemDriver(san.SanDriver,
                      'The invalid status is: %s.') % status)
             raise exception.InvalidSnapshot(msg)
 
-        self._create_and_copy_vdisk_data(snapshot['name'],
-                                         snapshot['id'],
-                                         volume['name'],
-                                         volume['id'])
+        self._create_and_copy_vdisk_data(
+            snapshot['name'],
+            snapshot['id'],
+            volume['name'],
+            volume['id'],
+            dest_vdisk_size=volume['size'] * units.Gi
+        )
 
         LOG.debug(
             'leave: create_volume_from_snapshot: create %(vol)s from '
@@ -1129,16 +1135,19 @@ class FlashSystemDriver(san.SanDriver,
         LOG.debug('enter: create_cloned_volume: create %(vol)s from %(src)s.',
                   {'src': src_volume['name'], 'vol': volume['name']})
 
-        if src_volume['size'] != volume['size']:
-            msg = _('create_cloned_volume: Source and destination '
-                    'size differ.')
+        if src_volume['size'] > volume['size']:
+            msg = _('create_cloned_volume: Source volume larger than '
+                    'destination volume')
             LOG.error(msg)
             raise exception.VolumeDriverException(message=msg)
 
-        self._create_and_copy_vdisk_data(src_volume['name'],
-                                         src_volume['id'],
-                                         volume['name'],
-                                         volume['id'])
+        self._create_and_copy_vdisk_data(
+            src_volume['name'],
+            src_volume['id'],
+            volume['name'],
+            volume['id'],
+            dest_vdisk_size=volume['size'] * units.Gi
+        )
 
         LOG.debug('leave: create_cloned_volume: create %(vol)s from %(src)s.',
                   {'src': src_volume['name'], 'vol': volume['name']})