From 9f26e65c62fd5a4a1fbf9048e3bfe857b18729c9 Mon Sep 17 00:00:00 2001
From: Shobhi Jain <shobhi.jain@intel.com>
Date: Wed, 7 Feb 2018 11:08:05 +0000
Subject: Replace neutron subnet creation with shade.

Function 'create_neutron_subnet' now uses shade client
instead of neutron client.

JIRA: YARDSTICK-890

Change-Id: I8eb5295cecd73742bfb5a7d0764af6f45ef0685e
Signed-off-by: Shobhi Jain <shobhi.jain@intel.com>
---
 yardstick/benchmark/scenarios/lib/create_subnet.py | 60 +++++++++++++---------
 yardstick/common/exceptions.py                     |  4 ++
 yardstick/common/openstack_utils.py                | 54 ++++++++++++++++---
 .../benchmark/scenarios/lib/test_create_subnet.py  | 60 ++++++++++++++++------
 .../tests/unit/common/test_openstack_utils.py      | 25 +++++++++
 5 files changed, 157 insertions(+), 46 deletions(-)

diff --git a/yardstick/benchmark/scenarios/lib/create_subnet.py b/yardstick/benchmark/scenarios/lib/create_subnet.py
index c34af8a9e..e383c99de 100644
--- a/yardstick/benchmark/scenarios/lib/create_subnet.py
+++ b/yardstick/benchmark/scenarios/lib/create_subnet.py
@@ -7,13 +7,12 @@
 # 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__)
 
@@ -28,9 +27,23 @@ class CreateSubnet(base.Scenario):
         self.context_cfg = context_cfg
         self.options = self.scenario_cfg['options']
 
-        self.openstack = self.options.get("openstack_paras", None)
-
-        self.neutron_client = op_utils.get_neutron_client()
+        self.network_name_or_id = self.options['network_name_or_id']
+        self.cidr = self.options.get('cidr')
+        self.ip_version = self.options.get('ip_version', 4)
+        self.enable_dhcp = self.options.get('enable_dhcp', False)
+        self.subnet_name = self.options.get('subnet_name')
+        self.tenant_id = self.options.get('tenant_id')
+        self.allocation_pools = self.options.get('allocation_pools')
+        self.gateway_ip = self.options.get('gateway_ip')
+        self.disable_gateway_ip = self.options.get('disable_gateway_ip', False)
+        self.dns_nameservers = self.options.get('dns_nameservers')
+        self.host_routes = self.options.get('host_routes')
+        self.ipv6_ra_mode = self.options.get('ipv6_ra_mode')
+        self.ipv6_address_mode = self.options.get('ipv6_address_mode')
+        self.use_default_subnetpool = self.options.get(
+            'use_default_subnetpool', False)
+
+        self.shade_client = openstack_utils.get_shade_client()
 
         self.setup_done = False
 
@@ -45,22 +58,23 @@ class CreateSubnet(base.Scenario):
         if not self.setup_done:
             self.setup()
 
-        openstack_paras = {'subnets': [self.openstack]}
-        subnet_id = op_utils.create_neutron_subnet(self.neutron_client,
-                                                   openstack_paras)
-        if subnet_id:
-            result.update({"subnet_create": 1})
-            LOG.info("Create subnet successful!")
-        else:
+        subnet_id = openstack_utils.create_neutron_subnet(
+            self.shade_client, self.network_name_or_id, cidr=self.cidr,
+            ip_version=self.ip_version, enable_dhcp=self.enable_dhcp,
+            subnet_name=self.subnet_name, tenant_id=self.tenant_id,
+            allocation_pools=self.allocation_pools, gateway_ip=self.gateway_ip,
+            disable_gateway_ip=self.disable_gateway_ip,
+            dns_nameservers=self.dns_nameservers, host_routes=self.host_routes,
+            ipv6_ra_mode=self.ipv6_ra_mode,
+            ipv6_address_mode=self.ipv6_address_mode,
+            use_default_subnetpool=self.use_default_subnetpool)
+        if not subnet_id:
             result.update({"subnet_create": 0})
             LOG.error("Create subnet failed!")
+            raise exceptions.ScenarioCreateSubnetError
 
-        check_result = subnet_id
-
-        try:
-            keys = self.scenario_cfg.get('output', '').split()
-        except KeyError:
-            pass
-        else:
-            values = [check_result]
-            return self._push_to_outputs(keys, values)
+        result.update({"subnet_create": 1})
+        LOG.info("Create subnet successful!")
+        keys = self.scenario_cfg.get('output', '').split()
+        values = [subnet_id]
+        return self._push_to_outputs(keys, values)
diff --git a/yardstick/common/exceptions.py b/yardstick/common/exceptions.py
index ade5b53a8..4245ce12f 100644
--- a/yardstick/common/exceptions.py
+++ b/yardstick/common/exceptions.py
@@ -104,3 +104,7 @@ class TaskRenderError(YardstickException):
 
 class ScenarioCreateNetworkError(YardstickException):
     message = 'Create Neutron Network Scenario failed'
+
+
+class ScenarioCreateSubnetError(YardstickException):
+    message = 'Create Neutron Subnet Scenario failed'
diff --git a/yardstick/common/openstack_utils.py b/yardstick/common/openstack_utils.py
index 9da37e64b..0421346e6 100644
--- a/yardstick/common/openstack_utils.py
+++ b/yardstick/common/openstack_utils.py
@@ -468,13 +468,55 @@ def delete_neutron_net(shade_client, network_id):
         return False
 
 
-def create_neutron_subnet(neutron_client, json_body):      # pragma: no cover
+def create_neutron_subnet(shade_client, network_name_or_id, cidr=None,
+                          ip_version=4, enable_dhcp=False, subnet_name=None,
+                          tenant_id=None, allocation_pools=None,
+                          gateway_ip=None, disable_gateway_ip=False,
+                          dns_nameservers=None, host_routes=None,
+                          ipv6_ra_mode=None, ipv6_address_mode=None,
+                          use_default_subnetpool=False):
+    """Create a subnet on a specified network.
+
+    :param network_name_or_id:(string) the unique name or ID of the
+                              attached network. If a non-unique name is
+                              supplied, an exception is raised.
+    :param cidr:(string) the CIDR.
+    :param ip_version:(int) the IP version.
+    :param enable_dhcp:(bool) whether DHCP is enable.
+    :param subnet_name:(string) the name of the subnet.
+    :param tenant_id:(string) the ID of the tenant who owns the network.
+    :param allocation_pools: A list of dictionaries of the start and end
+                            addresses for the allocation pools.
+    :param gateway_ip:(string) the gateway IP address.
+    :param disable_gateway_ip:(bool) whether gateway IP address is enabled.
+    :param dns_nameservers: A list of DNS name servers for the subnet.
+    :param host_routes: A list of host route dictionaries for the subnet.
+    :param ipv6_ra_mode:(string) IPv6 Router Advertisement mode.
+                        Valid values are: 'dhcpv6-stateful',
+                        'dhcpv6-stateless', or 'slaac'.
+    :param ipv6_address_mode:(string) IPv6 address mode.
+                             Valid values are: 'dhcpv6-stateful',
+                             'dhcpv6-stateless', or 'slaac'.
+    :param use_default_subnetpool:(bool) use the default subnetpool for
+                                  ``ip_version`` to obtain a CIDR. It is
+                                  required to pass ``None`` to the ``cidr``
+                                  argument when enabling this option.
+    :returns:(string) the subnet id.
+    """
     try:
-        subnet = neutron_client.create_subnet(body=json_body)
-        return subnet['subnets'][0]['id']
-    except Exception:  # pylint: disable=broad-except
-        log.error("Error [create_neutron_subnet")
-        raise Exception("operation error")
+        subnet = shade_client.create_subnet(
+            network_name_or_id, cidr=cidr, ip_version=ip_version,
+            enable_dhcp=enable_dhcp, subnet_name=subnet_name,
+            tenant_id=tenant_id, allocation_pools=allocation_pools,
+            gateway_ip=gateway_ip, disable_gateway_ip=disable_gateway_ip,
+            dns_nameservers=dns_nameservers, host_routes=host_routes,
+            ipv6_ra_mode=ipv6_ra_mode, ipv6_address_mode=ipv6_address_mode,
+            use_default_subnetpool=use_default_subnetpool)
+        return subnet['id']
+    except exc.OpenStackCloudException as o_exc:
+        log.error("Error [create_neutron_subnet(shade_client)]. "
+                  "Exception message: %s", o_exc.orig_message)
+        return None
 
 
 def create_neutron_router(neutron_client, json_body):      # pragma: no cover
diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_subnet.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_subnet.py
index 554b88acc..856e985c4 100644
--- a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_subnet.py
+++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_subnet.py
@@ -6,27 +6,53 @@
 # 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.create_subnet import CreateSubnet
+from yardstick.common import openstack_utils
+from yardstick.common import exceptions
+from yardstick.benchmark.scenarios.lib import create_subnet
 
 
 class CreateSubnetTestCase(unittest.TestCase):
 
-    @mock.patch('yardstick.common.openstack_utils.get_neutron_client')
-    @mock.patch('yardstick.common.openstack_utils.create_neutron_subnet')
-    def test_create_subnet(self, mock_get_neutron_client, mock_create_neutron_subnet):
-        options = {
-            'openstack_paras': {
-                'network_id': '123-123-123',
-                'name': 'yardstick_subnet',
-                'cidr': '10.10.10.0/24',
-                'ip_version': '4'
-            }
-        }
-        args = {"options": options}
-        obj = CreateSubnet(args, {})
-        obj.run({})
-        mock_get_neutron_client.assert_called_once()
-        mock_create_neutron_subnet.assert_called_once()
+    def setUp(self):
+
+        self._mock_create_neutron_subnet = mock.patch.object(
+            openstack_utils, 'create_neutron_subnet')
+        self.mock_create_neutron_subnet = (
+            self._mock_create_neutron_subnet.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(create_subnet, 'LOG')
+        self.mock_log = self._mock_log.start()
+        self.args = {'options': {'network_name_or_id': 'yardstick_net'}}
+        self.result = {"subnet_create": 0}
+
+        self._csubnet_obj = create_subnet.CreateSubnet(self.args, mock.ANY)
+        self.addCleanup(self._stop_mock)
+
+    def _stop_mock(self):
+        self._mock_create_neutron_subnet.stop()
+        self._mock_get_shade_client.stop()
+        self._mock_log.stop()
+
+    def test_run(self):
+        _uuid = uuidutils.generate_uuid()
+        self._csubnet_obj.scenario_cfg = {'output': 'id'}
+        self.mock_create_neutron_subnet.return_value = _uuid
+        output = self._csubnet_obj.run(self.result)
+        self.assertDictEqual({"subnet_create": 1}, self.result)
+        self.assertDictEqual({'id': _uuid}, output)
+        self.mock_log.info.asset_called_once_with('Create subnet successful!')
+
+    def test_run_fail(self):
+        self._csubnet_obj.scenario_cfg = {'output': 'id'}
+        self.mock_create_neutron_subnet.return_value = None
+        with self.assertRaises(exceptions.ScenarioCreateSubnetError):
+            self._csubnet_obj.run(self.result)
+        self.assertDictEqual({"subnet_create": 0}, self.result)
+        self.mock_log.error.assert_called_once_with('Create subnet failed!')
diff --git a/yardstick/tests/unit/common/test_openstack_utils.py b/yardstick/tests/unit/common/test_openstack_utils.py
index a63661025..cf5c206a5 100644
--- a/yardstick/tests/unit/common/test_openstack_utils.py
+++ b/yardstick/tests/unit/common/test_openstack_utils.py
@@ -108,3 +108,28 @@ class CreateNeutronNetTestCase(unittest.TestCase):
                                                     self.network_name)
         mock_logger.error.assert_called_once()
         self.assertIsNone(output)
+
+
+class CreateNeutronSubnetTestCase(unittest.TestCase):
+
+    def setUp(self):
+        self.mock_shade_client = mock.Mock()
+        self.network_name_or_id = 'name_or_id'
+        self.mock_shade_client.create_subnet = mock.Mock()
+
+    def test_create_neutron_subnet(self):
+        _uuid = uuidutils.generate_uuid()
+        self.mock_shade_client.create_subnet.return_value = {'id': _uuid}
+        output = openstack_utils.create_neutron_subnet(
+            self.mock_shade_client, self.network_name_or_id)
+        self.assertEqual(_uuid, output)
+
+    @mock.patch.object(openstack_utils, 'log')
+    def test_create_neutron_subnet_exception(self, mock_logger):
+        self.mock_shade_client.create_subnet.side_effect = (
+            exc.OpenStackCloudException('error message'))
+
+        output = openstack_utils.create_neutron_subnet(
+            self.mock_shade_client, self.network_name_or_id)
+        mock_logger.error.assert_called_once()
+        self.assertIsNone(output)
-- 
cgit