Add Neutron LoadBalancer v1 create and list vips

Enable benchmarking of the Neutron LoadBalancer v1
lb-vip-create and lb-vip-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: I8a4f85bb62ae2a44be0a25d9a8327fd1ee48336b
This commit is contained in:
Kiran 2015-07-14 20:05:10 +05:30
parent f139d3bd5c
commit 2352e8565e
7 changed files with 167 additions and 0 deletions

View File

@ -163,6 +163,29 @@
failure_rate:
max: 0
NeutronLoadbalancerV1.create_and_list_vips:
-
args:
vip_create_args: {}
runner:
type: "constant"
times: 20
concurrency: 10
context:
users:
tenants: 5
users_per_tenant: 4
network: {}
quotas:
neutron:
network: -1
subnet: -1
pool: -1
vip: -1
sla:
failure_rate:
max: 0
NeutronNetworks.create_and_update_networks:
-
args:

View File

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

View File

@ -13,6 +13,7 @@
from rally import consts
from rally.plugins.openstack import scenario
from rally.plugins.openstack.scenarios.neutron import utils
from rally.task import atomic
from rally.task import validation
@ -85,3 +86,30 @@ class NeutronLoadbalancerV1(utils.NeutronScenario):
pools = self._create_v1_pools(networks, **pool_create_args)
for pool in pools:
self._update_v1_pool(pool, **pool_update_args)
@validation.restricted_parameters(["pool_id", "subnet_id"],
subdict="vip_create_args")
@validation.required_neutron_extensions("lbaas")
@validation.required_services(consts.Service.NEUTRON)
@validation.required_openstack(admin=True)
@validation.required_contexts("network")
@scenario.configure(context={"cleanup": ["neutron"]})
def create_and_list_vips(self, pool_create_args=None,
vip_create_args=None):
"""Create a vip(v1) and then list vips(v1).
Measure the "neutron lb-vip-create" and "neutron lb-vip-list" command
performance. The scenario creates a vip for every pool created and
then lists vips.
:param vip_create_args: dict, POST /lb/vips request options
:param pool_create_args: dict, POST /lb/pools request options
"""
vip_create_args = vip_create_args or {}
pool_create_args = pool_create_args or {}
networks = self.context.get("tenant", {}).get("networks", [])
pools = self._create_v1_pools(networks, **pool_create_args)
with atomic.ActionTimer(self, "neutron.create_%s_vips" % len(pools)):
for pool in pools:
self._create_v1_vip(pool, **vip_create_args)
self._list_v1_vips()

View File

@ -31,6 +31,7 @@ class NeutronScenario(scenario.OpenStackScenario):
# TODO(rkiran): modify in case LBaaS-v2 requires
LB_METHOD = "ROUND_ROBIN"
LB_PROTOCOL = "HTTP"
LB_PROTOCOL_PORT = 80
def _warn_about_deprecated_name_kwarg(self, resource, kwargs):
"""Warn about use of a deprecated 'name' kwarg and replace it.
@ -347,3 +348,23 @@ class NeutronScenario(scenario.OpenStackScenario):
self._warn_about_deprecated_name_kwarg(pool, pool_update_args)
body = {"pool": pool_update_args}
return self.clients("neutron").update_pool(pool["pool"]["id"], body)
def _create_v1_vip(self, pool, **vip_create_args):
"""Create VIP(v1)
:parm pool: dict, neutron lb-pool
:parm vip_create_args: dict, POST /lb/vips request options
:returns: dict, neutron lb vip
"""
args = {"protocol": self.LB_PROTOCOL,
"protocol_port": self.LB_PROTOCOL_PORT,
"name": self._generate_random_name("rally_vip_"),
"pool_id": pool["pool"]["id"],
"subnet_id": pool["pool"]["subnet_id"]}
args.update(vip_create_args)
return self.clients("neutron").create_vip({"vip": args})
@atomic.action_timer("neutron.list_vips")
def _list_v1_vips(self, **kwargs):
"""Return user lb vip list(v1)."""
return self.clients("neutron").list_vips(**kwargs)

View File

@ -1035,6 +1035,7 @@ class FakeNeutronClient(object):
self.__routers = {}
self.__ports = {}
self.__pools = {}
self.__vips = {}
self.__tenant_id = kwargs.get("tenant_id", generate_uuid())
self.format = "json"
@ -1098,6 +1099,23 @@ class FakeNeutronClient(object):
self.__pools[pool_id] = pool
return {"pool": pool}
def create_vip(self, data):
vip = setup_dict(data["vip"],
required=["protocol_port", "protocol", "subnet_id",
"pool_id"],
defaults={"name": generate_name("vip_"),
"admin_state_up": True})
if (vip["subnet_id"] not in self.__subnets) or (vip["pool_id"] not in
self.__pools):
raise neutron_exceptions.NeutronClientException
vip_id = generate_uuid()
vip.update({"id": vip_id,
"status": "PENDING_CREATE",
"tenant_id": self.__tenant_id})
self.__vips[vip_id] = vip
return {"vip": vip}
def create_port(self, data):
port = setup_dict(data["port"],
required=["network_id"],
@ -1234,6 +1252,10 @@ class FakeNeutronClient(object):
pools = self._filter(self.__pools.values(), search_opts)
return {"pools": pools}
def list_vips(self, **search_opts):
vips = self._filter(self.__vips.values(), search_opts)
return {"vips": vips}
def list_ports(self, **search_opts):
ports = self._filter(self.__ports.values(), search_opts)
return {"ports": ports}

View File

@ -125,3 +125,36 @@ class NeutronLoadbalancerv1TestCase(test.TestCase):
for pool in pools:
neutron_scenario._update_v1_pool.assert_called_once_with(
pool, **pool_update_args)
@ddt.data(
{},
{"vip_create_args": None},
{"vip_create_args": {}},
{"vip_create_args": {"name": "given-vip-name"}},
{"pool_create_args": None},
{"pool_create_args": {}},
{"pool_create_args": {"name": "given-pool-name"}},
)
@ddt.unpack
def test_create_and_list_vips(self, pool_create_args=None,
vip_create_args=None):
neutron_scenario = loadbalancer_v1.NeutronLoadbalancerV1(
self._get_context())
pools = [{
"pool": {
"id": "pool-id"
}
}]
vip_data = vip_create_args or {}
pool_data = pool_create_args or {}
networks = self._get_context()["tenant"]["networks"]
neutron_scenario._create_v1_pools = mock.Mock(return_value=pools)
neutron_scenario._create_v1_vip = mock.Mock()
neutron_scenario._list_v1_vips = mock.Mock()
neutron_scenario.create_and_list_vips(
pool_create_args=pool_create_args, vip_create_args=vip_create_args)
neutron_scenario._create_v1_pools.assert_called_once_with(
networks, **pool_data)
neutron_scenario._create_v1_vip.assert_has_calls(
[mock.call(pool, **vip_data) for pool in pools])
neutron_scenario._list_v1_vips.assert_called_once_with()

View File

@ -476,6 +476,16 @@ class NeutronScenarioTestCase(test.ScenarioTestCase):
self._test_atomic_action_timer(scenario.atomic_actions(),
"neutron.list_pools")
def test_list_v1_vips(self):
scenario = utils.NeutronScenario()
vips_list = []
vips_dict = {"vips": vips_list}
self.clients("neutron").list_vips.return_value = vips_dict
return_vips_dict = scenario._list_v1_vips()
self.assertEqual(vips_dict, return_vips_dict)
self._test_atomic_action_timer(scenario.atomic_actions(),
"neutron.list_vips")
class NeutronScenarioFunctionalTestCase(test.FakeClientsScenarioTestCase):
@ -572,3 +582,29 @@ class NeutronLoadbalancerScenarioTestCase(test.ScenarioTestCase):
if atomic_action:
self._test_atomic_action_timer(
neutron_scenario.atomic_actions(), "neutron.create_pool")
@ddt.data(
{},
{"vip_create_args": {}},
{"vip_create_args": {"name": "given-name"}},
)
@ddt.unpack
def test__create_v1_vip(self, vip_create_args=None):
neutron_scenario = utils.NeutronScenario()
vip = {"vip": {"id": "vip-id"}}
pool = {"pool": {"id": "pool-id", "subnet_id": "subnet-id"}}
vip_create_args = vip_create_args or {}
if vip_create_args.get("name") is None:
neutron_scenario._generate_random_name = mock.Mock(
return_value="random_name")
self.clients("neutron").create_vip.return_value = vip
args = {"protocol_port": 80, "protocol": "HTTP", "name": "random_name",
"subnet_id": pool["pool"]["subnet_id"],
"pool_id": pool["pool"]["id"]}
args.update(vip_create_args)
expected_vip_data = {"vip": args}
resultant_vip = neutron_scenario._create_v1_vip(
pool, **vip_create_args)
self.assertEqual(resultant_vip, vip)
self.clients("neutron").create_vip.assert_called_once_with(
expected_vip_data)