Replace nova attach volume to server with shade client. 61/54561/21
authorShobhi Jain <shobhi.jain@intel.com>
Wed, 28 Mar 2018 11:19:35 +0000 (12:19 +0100)
committerShobhi Jain <shobhi.jain@intel.com>
Mon, 30 Apr 2018 08:53:45 +0000 (09:53 +0100)
Function attach_volume_to_server now uses shade client
instead of nova client.

JIRA: YARDSTICK-1088

Change-Id: Id00df672c2c195b5c338cbbc30ddf2742a4e4d29
Signed-off-by: Shobhi Jain <shobhi.jain@intel.com>
yardstick/benchmark/scenarios/lib/attach_volume.py
yardstick/common/exceptions.py
yardstick/common/openstack_utils.py
yardstick/tests/unit/benchmark/scenarios/lib/test_attach_volume.py
yardstick/tests/unit/common/test_openstack_utils.py

index 8812496..96dd130 100644 (file)
@@ -6,30 +6,31 @@
 # which accompanies this distribution, and is available at
 # http://www.apache.org/licenses/LICENSE-2.0
 ##############################################################################
-
-from __future__ import print_function
-from __future__ import absolute_import
-
 import logging
 
 from yardstick.benchmark.scenarios import base
-import yardstick.common.openstack_utils as op_utils
+from yardstick.common import openstack_utils
+from yardstick.common import exceptions
 
 LOG = logging.getLogger(__name__)
 
 
 class AttachVolume(base.Scenario):
-    """Attach a volmeu to an instance"""
+    """Attach a volume to an instance"""
 
     __scenario_type__ = "AttachVolume"
 
     def __init__(self, scenario_cfg, context_cfg):
         self.scenario_cfg = scenario_cfg
         self.context_cfg = context_cfg
-        self.options = self.scenario_cfg['options']
+        self.options = self.scenario_cfg["options"]
 
-        self.server_id = self.options.get("server_id", "TestServer")
-        self.volume_id = self.options.get("volume_id", None)
+        self.server_name_or_id = self.options["server_name_or_id"]
+        self.volume_name_or_id = self.options["volume_name_or_id"]
+        self.device = self.options.get("device")
+        self.wait = self.options.get("wait", True)
+        self.timeout = self.options.get("timeout")
+        self.shade_client = openstack_utils.get_shade_client()
 
         self.setup_done = False
 
@@ -44,10 +45,14 @@ class AttachVolume(base.Scenario):
         if not self.setup_done:
             self.setup()
 
-        status = op_utils.attach_server_volume(self.server_id,
-                                               self.volume_id)
+        status = openstack_utils.attach_volume_to_server(
+            self.shade_client, self.server_name_or_id, self.volume_name_or_id,
+            device=self.device, wait=self.wait, timeout=self.timeout)
+
+        if not status:
+            result.update({"attach_volume": 0})
+            LOG.error("Attach volume to server failed!")
+            raise exceptions.ScenarioAttachVolumeError
 
-        if status:
-            LOG.info("Attach volume to server successful!")
-        else:
-            LOG.info("Attach volume to server failed!")
+        result.update({"attach_volume": 1})
+        LOG.info("Attach volume to server successful!")
index 7347061..c235abc 100644 (file)
@@ -190,3 +190,7 @@ class ScenarioCreateKeypairError(YardstickException):
 
 class ScenarioDeleteKeypairError(YardstickException):
     message = 'Nova Delete Keypair Scenario failed'
+
+
+class ScenarioAttachVolumeError(YardstickException):
+    message = 'Nova Attach Volume Scenario failed'
index 0902d29..0a3cfb5 100644 (file)
@@ -264,17 +264,36 @@ def create_instance_and_wait_for_active(shade_client, name, image,
                   "Exception message, '%s'", o_exc.orig_message)
 
 
-def attach_server_volume(server_id, volume_id,
-                         device=None):    # pragma: no cover
+def attach_volume_to_server(shade_client, server_name_or_id, volume_name_or_id,
+                            device=None, wait=True, timeout=None):
+    """Attach a volume to a server.
+
+    This will attach a volume, described by the passed in volume
+    dict, to the server described by the passed in server dict on the named
+    device on the server.
+
+    If the volume is already attached to the server, or generally not
+    available, then an exception is raised. To re-attach to a server,
+    but under a different device, the user must detach it first.
+
+    :param server_name_or_id:(string) The server name or id to attach to.
+    :param volume_name_or_id:(string) The volume name or id to attach.
+    :param device:(string) The device name where the volume will attach.
+    :param wait:(bool) If true, waits for volume to be attached.
+    :param timeout: Seconds to wait for volume attachment. None is forever.
+
+    :returns: True if attached successful, False otherwise.
+    """
     try:
-        get_nova_client().volumes.create_server_volume(server_id,
-                                                       volume_id, device)
-    except Exception:  # pylint: disable=broad-except
-        log.exception("Error [attach_server_volume(nova_client, '%s', '%s')]",
-                      server_id, volume_id)
-        return False
-    else:
+        server = shade_client.get_server(name_or_id=server_name_or_id)
+        volume = shade_client.get_volume(volume_name_or_id)
+        shade_client.attach_volume(
+            server, volume, device=device, wait=wait, timeout=timeout)
         return True
+    except exc.OpenStackCloudException as o_exc:
+        log.error("Error [attach_volume_to_server(shade_client)]. "
+                  "Exception message: %s", o_exc.orig_message)
+        return False
 
 
 def delete_instance(shade_client, name_or_id, wait=False, timeout=180,
index 2964ecc..bb7fa45 100644 (file)
@@ -6,21 +6,51 @@
 # which accompanies this distribution, and is available at
 # http://www.apache.org/licenses/LICENSE-2.0
 ##############################################################################
+from oslo_utils import uuidutils
 import unittest
 import mock
 
-from yardstick.benchmark.scenarios.lib.attach_volume import AttachVolume
+from yardstick.common import openstack_utils
+from yardstick.common import exceptions
+from yardstick.benchmark.scenarios.lib import attach_volume
 
 
 class AttachVolumeTestCase(unittest.TestCase):
 
-    @mock.patch('yardstick.common.openstack_utils.attach_server_volume')
-    def test_attach_volume(self, mock_attach_server_volume):
-        options = {
-            'volume_id': '123-456-000',
-            'server_id': '000-123-456'
-        }
-        args = {"options": options}
-        obj = AttachVolume(args, {})
-        obj.run({})
-        mock_attach_server_volume.assert_called_once()
+    def setUp(self):
+
+        self._mock_attach_volume_to_server = mock.patch.object(
+            openstack_utils, 'attach_volume_to_server')
+        self.mock_attach_volume_to_server = (
+            self._mock_attach_volume_to_server.start())
+        self._mock_get_shade_client = mock.patch.object(
+            openstack_utils, 'get_shade_client')
+        self.mock_get_shade_client = self._mock_get_shade_client.start()
+        self._mock_log = mock.patch.object(attach_volume, 'LOG')
+        self.mock_log = self._mock_log.start()
+        _uuid = uuidutils.generate_uuid()
+        self.args = {'options': {'server_name_or_id': _uuid,
+                                 'volume_name_or_id': _uuid}}
+        self.result = {}
+        self.addCleanup(self._stop_mock)
+        self.attachvol_obj = attach_volume.AttachVolume(self.args, mock.ANY)
+
+    def _stop_mock(self):
+        self._mock_attach_volume_to_server.stop()
+        self._mock_get_shade_client.stop()
+        self._mock_log.stop()
+
+    def test_run(self):
+        self.mock_attach_volume_to_server.return_value = True
+        self.assertIsNone(self.attachvol_obj.run(self.result))
+        self.assertEqual({'attach_volume': 1}, self.result)
+        self.mock_log.info.asset_called_once_with(
+            'Attach volume to server successful!')
+
+    def test_run_fail(self):
+        self.mock_attach_volume_to_server.return_value = False
+        with self.assertRaises(exceptions.ScenarioAttachVolumeError):
+            self.attachvol_obj.run(self.result)
+        self.assertEqual({'attach_volume': 0}, self.result)
+        self.mock_log.error.assert_called_once_with(
+            'Attach volume to server failed!')
index 4dc4a70..3441ad2 100644 (file)
@@ -445,3 +445,25 @@ class DeleteKeypairTestCase(unittest.TestCase):
                                                 'key_name')
         mock_logger.error.assert_called_once()
         self.assertFalse(output)
+
+
+class AttachVolumeToServerTestCase(unittest.TestCase):
+
+    def test_attach_volume_to_server(self):
+        self.mock_shade_client = mock.Mock()
+        self.mock_shade_client.get_server.return_value = {'server_dict'}
+        self.mock_shade_client.get_volume.return_value = {'volume_dict'}
+        self.mock_shade_client.attach_volume.return_value = True
+        output = openstack_utils.attach_volume_to_server(
+            self.mock_shade_client, 'server_name_or_id', 'volume_name_or_id')
+        self.assertTrue(output)
+
+    @mock.patch.object(openstack_utils, 'log')
+    def test_attach_volume_to_server_fail(self, mock_logger):
+        self.mock_shade_client = mock.Mock()
+        self.mock_shade_client.attach_volume.side_effect = (
+            exc.OpenStackCloudException('error message'))
+        output = openstack_utils.attach_volume_to_server(
+            self.mock_shade_client, 'server_name_or_id', 'volume_name_or_id')
+        mock_logger.error.assert_called_once()
+        self.assertFalse(output)