Add Neutron Loadbalancer v1 create and list pool

Enable benchmarking of the Neutron LoadBalancer v1
pool-create and pool-list APIs. Due to the different
API scheme and confusing naming conventions in
Neutron (LB is v1 API and LBaaS for v2 API) the
appropriate code is explicitly marked with 'v1'
since this only implements the API v1 benchmarking.

Change-Id: If51f6286be49724c0bc4ae343815704f01153e97
This commit is contained in:
Maplalabs 2015-05-22 15:43:36 +05:30
parent ed2996dac1
commit bc9e8d0660
7 changed files with 201 additions and 0 deletions

View File

@ -91,6 +91,28 @@
failure_rate:
max: 20
NeutronLoadbalancerV1.create_and_list_pools:
-
args:
pool_create_args: {}
runner:
type: "constant"
times: 20
concurrency: 10
context:
users:
tenants: 1
users_per_tenant: 1
network: {}
quotas:
neutron:
network: -1
subnet: -1
pool: -1
sla:
failure_rate:
max: 0
NeutronNetworks.create_and_update_networks:
-
args:

View File

@ -52,6 +52,10 @@ class NeutronQuotas(object):
"security_group_rule": {
"type": "integer",
"minimum": -1
},
"pool": {
"type": "integer",
"minimum": -1
}
}
}

View File

@ -0,0 +1,38 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from rally.benchmark.scenarios import base
from rally.benchmark import validation
from rally import consts
from rally.plugins.openstack.scenarios.neutron import utils
class NeutronLoadbalancerV1(utils.NeutronScenario):
"""Benchmark scenarios for Neutron Loadbalancer v1."""
@validation.restricted_parameters("subnet_id", subdict="pool_create_args")
@validation.required_services(consts.Service.NEUTRON)
@validation.required_openstack(users=True)
@validation.required_contexts("network")
@base.scenario(context={"cleanup": ["neutron"]})
def create_and_list_pools(self, pool_create_args=None):
"""Create a pool(v1) and then list pools(v1).
Measure the "neutron lb-pool-list" command performance.
The scenario creates a pool for every subnet and then lists pools.
:param pool_create_args: dict, POST /lb/pools request options
"""
for net in self.context.get("tenant", {}).get("networks", []):
for subnet_id in net["subnets"]:
self._create_v1_pool(subnet_id, **pool_create_args)
self._list_v1_pools()

View File

@ -28,6 +28,9 @@ class NeutronScenario(base.Scenario):
RESOURCE_NAME_PREFIX = "rally_net_"
RESOURCE_NAME_LENGTH = 16
SUBNET_IP_VERSION = 4
# TODO(rkiran): modify in case LBaaS-v2 requires
LB_METHOD = "ROUND_ROBIN"
LB_PROTOCOL = "HTTP"
@base.atomic_action_timer("neutron.create_network")
def _create_network(self, network_create_args):
@ -287,3 +290,22 @@ class NeutronScenario(base.Scenario):
"""
self.clients("neutron").remove_interface_router(
router["id"], {"subnet_id": subnet["id"]})
@base.atomic_action_timer("neutron.create_pool")
def _create_v1_pool(self, subnet_id, **pool_create_args):
"""Create pool(v1)
:parm subnet_id: str, neutron subnet-id
:parm pool_create_args: dict, POST /lb/pools request options
:returns: obj, neutron lb pool
"""
args = {"lb_method": self.LB_METHOD, "protocol": self.LB_PROTOCOL,
"name": self._generate_random_name("rally_pool_"),
"subnet_id": subnet_id}
args.update(pool_create_args)
return self.clients("neutron").create_pool({"pool": args})
@base.atomic_action_timer("neutron.list_pools")
def _list_v1_pools(self, **kwargs):
"""Return user lb pool list(v1)."""
return self.clients("neutron").list_pools()

View File

@ -1064,6 +1064,7 @@ class FakeNeutronClient(object):
self.__subnets = {}
self.__routers = {}
self.__ports = {}
self.__pools = {}
self.__tenant_id = kwargs.get("tenant_id", generate_uuid())
self.format = "json"
@ -1112,6 +1113,21 @@ class FakeNeutronClient(object):
self.__networks[network_id] = network
return {"network": network}
def create_pool(self, data):
pool = setup_dict(data["pool"],
required=["lb_method", "protocol", "subnet_id"],
defaults={"name": generate_name("pool_"),
"admin_state_up": True})
if pool["subnet_id"] not in self.__subnets:
raise neutron_exceptions.NeutronClientException
pool_id = generate_uuid()
pool.update({"id": pool_id,
"status": "PENDING_CREATE",
"tenant_id": self.__tenant_id})
self.__pools[pool_id] = pool
return {"pool": pool}
def create_port(self, data):
port = setup_dict(data["port"],
required=["network_id"],
@ -1238,6 +1254,10 @@ class FakeNeutronClient(object):
nets = self._filter(self.__networks.values(), search_opts)
return {"networks": nets}
def list_pools(self, **search_opts):
pools = self._filter(self.__pools.values(), search_opts)
return {"pools": pools}
def list_ports(self, **search_opts):
ports = self._filter(self.__ports.values(), search_opts)
return {"ports": ports}

View File

@ -0,0 +1,45 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import mock
from rally.plugins.openstack.scenarios.neutron import loadbalancer_v1
from tests.unit import test
class NeutronLoadbalancerv1TestCase(test.TestCase):
def _get_context(self):
return {
"user": {"id": "fake_user", "tenant_id": "fake_tenant"},
"tenant": {"id": "fake_tenant",
"networks": [{"id": "fake_net",
"subnets": ["fake_subnet"]}]}}
def _validate_scenario(self, pool_create_args):
neutron_scenario = loadbalancer_v1.NeutronLoadbalancerV1(
self._get_context())
neutron_scenario._create_v1_pool = mock.Mock()
neutron_scenario._list_v1_pools = mock.Mock()
neutron_scenario.create_and_list_pools(
pool_create_args=pool_create_args)
for net in self._get_context()["tenant"]["networks"]:
for subnet_id in net["subnets"]:
neutron_scenario._create_v1_pool.assert_called_once_with(
subnet_id, **pool_create_args)
neutron_scenario._list_v1_pools.assert_called_once_with()
def test_create_and_list_pools_default(self):
self._validate_scenario(pool_create_args={})
def test_create_and_list_pools_explicit(self):
self._validate_scenario(pool_create_args={"name": "given-name"})

View File

@ -391,6 +391,56 @@ class NeutronScenarioTestCase(test.ClientsTestCase):
{"allocation_pools": []},
"10.10.10.0/24")] * subnets_per_network)
def test_create_v1_pool_explicit(self):
neutron_scenario = utils.NeutronScenario()
lb_method = "LEAST_CONNECTIONS"
subnet = "fake-id"
pool = mock.Mock()
self.clients("neutron").create_pool.return_value = pool
# Explicit options
pool_data = {"lb_method": lb_method, "name": "explicit-name"}
args = {"lb_method": "ROUND_ROBIN", "protocol": "HTTP",
"name": "random_name", "subnet_id": subnet}
args.update(pool_data)
expected_pool_data = {"pool": args}
pool = neutron_scenario._create_v1_pool(
subnet_id=subnet, **pool_data)
self.clients("neutron").create_pool.assert_called_once_with(
expected_pool_data)
self._test_atomic_action_timer(
neutron_scenario.atomic_actions(), "neutron.create_pool")
@mock.patch(NEUTRON_UTILS + "NeutronScenario._generate_random_name")
def test_create_v1_pool_default(self, mock_random_name):
neutron_scenario = utils.NeutronScenario()
random_name = "random_name"
subnet = "fake-id"
pool = mock.Mock()
self.clients("neutron").create_pool.return_value = pool
mock_random_name.return_value = random_name
# Random pool name
pool_data = {}
args = {"lb_method": "ROUND_ROBIN", "protocol": "HTTP",
"name": "random_name", "subnet_id": subnet}
args.update(pool_data)
expected_pool_data = {"pool": args}
pool = neutron_scenario._create_v1_pool(
subnet_id=subnet, **pool_data)
self.clients("neutron").create_pool.assert_called_once_with(
expected_pool_data)
self._test_atomic_action_timer(
neutron_scenario.atomic_actions(), "neutron.create_pool")
def test_list_v1_pools(self):
scenario = utils.NeutronScenario()
pools_list = []
pools_dict = {"pools": pools_list}
self.clients("neutron").list_pools.return_value = pools_dict
return_pools_dict = scenario._list_v1_pools()
self.assertEqual(pools_dict, return_pools_dict)
self._test_atomic_action_timer(scenario.atomic_actions(),
"neutron.list_pools")
class NeutronScenarioFunctionalTestCase(test.FakeClientsTestCase):