Merge "New rally scenario: bind port"

This commit is contained in:
Zuul 2019-07-05 13:55:30 +00:00 committed by Gerrit Code Review
commit a58b876be9
10 changed files with 341 additions and 1 deletions

View File

@ -642,6 +642,31 @@
failure_rate:
max: 20
NeutronNetworks.create_and_bind_ports:
-
args:
ports_per_network: 5
runner:
type: "constant"
times: {{smoke or 10}}
concurrency: {{smoke or 5}}
context:
users:
tenants: {{smoke or 2}}
users_per_tenant: {{smoke or 1}}
roles:
- admin
quotas:
neutron:
network: -1
subnet: -1
port: -1
network: {}
networking_agents: {}
sla:
failure_rate:
max: 0
NeutronSubnets.delete_subnets:
-
runner:

View File

@ -28,5 +28,12 @@ OPTS = {"openstack": [
default=False,
help="Whether Neutron API is older then OpenStack Newton or "
"not. Based in this option, some external fields for "
"identifying resources can be applied.")
"identifying resources can be applied."),
cfg.ListOpt("neutron_bind_l2_agent_types",
# default to agent types used in gate jobs
default=[
"Open vSwitch agent",
"Linux bridge agent",
],
help="Neutron L2 agent types to find hosts to bind"),
]}

View File

@ -0,0 +1,45 @@
# Copyright 2019 Ericsson Software Technology
#
# 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.common import logging
from rally.common import validation
from rally.task import context
from rally_openstack import consts
from rally_openstack import osclients
LOG = logging.getLogger(__name__)
@validation.add("required_platform", platform="openstack", admin=True)
@context.configure(name="networking_agents", platform="openstack", order=349)
class NetworkingAgents(context.Context):
"""This context supports querying Neutron agents in Rally."""
CONFIG_SCHEMA = {
"type": "object",
"$schema": consts.JSON_SCHEMA,
"additionalProperties": False,
}
def setup(self):
nc = osclients.Clients(self.context["admin"]["credential"]).neutron()
agents = nc.list_agents()["agents"]
# NOTE(bence romsics): If you ever add input parameters to this context
# beware that here we use the same key in self.context as is used for
# parameter passing, so we'll overwrite it.
self.context["networking_agents"] = agents
def cleanup(self):
"""Neutron agents were not created by Rally, so nothing to do."""

View File

@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
from rally.common import cfg
from rally.common import logging
from rally.task import validation
from rally_openstack import consts
@ -20,6 +22,9 @@ from rally_openstack import scenario
from rally_openstack.scenarios.neutron import utils
LOG = logging.getLogger(__name__)
"""Scenarios for Neutron."""
@ -510,6 +515,75 @@ class CreateAndDeletePorts(utils.NeutronScenario):
self._delete_port(port)
@validation.add("number", param_name="ports_per_network", minval=1,
integer_only=True)
@validation.add("required_services",
services=[consts.Service.NEUTRON])
@validation.add("required_contexts", contexts=["network", "networking_agents"])
@validation.add("required_platform", platform="openstack",
users=True, admin=True)
@scenario.configure(context={"cleanup@openstack": ["neutron"],
"networking_agents": {},
"network": {}},
name="NeutronNetworks.create_and_bind_ports",
platform="openstack")
class CreateAndBindPorts(utils.NeutronScenario):
def run(self, ports_per_network=1):
"""Bind a given number of ports.
Measure the performance of port binding and all of its pre-requisites:
* openstack network create
* openstack subnet create --ip-version 4
* openstack subnet create --ip-version 6
* openstack port create
* openstack port update (binding)
:param ports_per_network: int, number of ports for one network
"""
# NOTE(bence romsics): Find a host where we can expect to bind
# successfully. Look at agent types used in the gate.
host_to_bind = None
for agent in self.context["networking_agents"]:
if (agent["admin_state_up"] and
agent["alive"] and
agent["agent_type"] in
cfg.CONF.openstack.neutron_bind_l2_agent_types):
host_to_bind = agent["host"]
if host_to_bind is None:
raise Exception(
"No live agent of type(s) to bind was found: %s" %
", ".join(cfg.CONF.openstack.neutron_bind_l2_agent_types))
tenant_id = self.context["tenant"]["id"]
for network in self.context["tenants"][tenant_id]["networks"]:
wrapped_network = {"network": network}
self._create_subnet(
wrapped_network,
start_cidr="10.2.0.0/24",
subnet_create_args={},
)
self._create_subnet(
wrapped_network,
start_cidr="2001:db8:1:1::/64",
subnet_create_args={},
)
for i in range(ports_per_network):
port = self._create_port(wrapped_network, port_create_args={})
# port bind needs admin role
self._update_port(
port,
port_update_args={
"device_owner": "compute:nova",
"device_id": "ba805478-85ff-11e9-a2e4-2b8dea218fc8",
"binding:host_id": host_to_bind,
},
)
@validation.add("required_services",
services=[consts.Service.NEUTRON])
@validation.add("required_platform", platform="openstack", users=True)

View File

@ -0,0 +1,21 @@
{
"Dummy.openstack": [
{
"args": {
"sleep": 0.1
},
"runner": {
"type": "constant",
"times": 4,
"concurrency": 2
},
"context": {
"users": {
"tenants": 1,
"users_per_tenant": 2
},
"networking_agents": {}
}
}
]
}

View File

@ -0,0 +1,14 @@
---
Dummy.openstack:
-
args:
sleep: 0.1
runner:
type: "constant"
times: 4
concurrency: 2
context:
users:
tenants: 1
users_per_tenant: 2
networking_agents: {}

View File

@ -0,0 +1,35 @@
{
"NeutronNetworks.create_and_bind_ports": [
{
"args": {
"ports_per_network": 2
},
"runner": {
"type": "constant",
"times": 10,
"concurrency": 5
},
"context": {
"users": {
"tenants": 2,
"users_per_tenant": 3
},
"roles": ["admin"],
"quotas": {
"neutron": {
"network": -1,
"subnet": -1,
"port": -1
}
},
"network": {},
"networking_agents": {}
},
"sla": {
"failure_rate": {
"max": 0
}
}
}
]
}

View File

@ -0,0 +1,25 @@
---
NeutronNetworks.create_and_bind_ports:
-
args:
ports_per_network: 2
runner:
type: "constant"
times: 10
concurrency: 5
context:
users:
tenants: 2
users_per_tenant: 3
roles:
- admin
quotas:
neutron:
network: -1
subnet: -1
port: -1
network: {}
networking_agents: {}
sla:
failure_rate:
max: 0

View File

@ -0,0 +1,55 @@
# Copyright 2019 Ericsson Software Technology
#
# 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_openstack.contexts.network import networking_agents
from tests.unit import test
CTX = "rally_openstack.contexts.network"
class NetworkingAgentsTestCase(test.TestCase):
def setUp(self):
super(NetworkingAgentsTestCase, self).setUp()
self.config = {}
self.context = test.get_test_context()
self.context.update({
"users": [
{"id": 1,
"tenant_id": "tenant1",
"credential": mock.Mock()},
],
"admin": {
"credential": mock.Mock(),
},
"config": {
"networking_agents": self.config,
},
})
@mock.patch("rally_openstack.osclients.Clients")
def test_setup(self, mock_clients):
context = networking_agents.NetworkingAgents(self.context)
context.setup()
mock_clients.assert_has_calls([
mock.call().neutron().list_agents(),
])
def test_cleanup(self):
# NOTE(stpierre): Test that cleanup is not abstract
networking_agents.NetworkingAgents(
{"task": mock.MagicMock()}).cleanup()

View File

@ -426,6 +426,45 @@ class NeutronNetworksTestCase(test.ScenarioTestCase):
scenario._update_port.assert_has_calls(
[mock.call(p, port_update_args) for p in ports])
def test_create_and_bind_ports(self):
ports_per_network = 2
ports = [mock.Mock() for _ in range(ports_per_network)]
port_update_args = {
"device_owner": "compute:nova",
"device_id": "ba805478-85ff-11e9-a2e4-2b8dea218fc8",
"binding:host_id": "fake-host",
}
context = {
"tenant": {"id": "fake-tenant-id"},
"tenants": {
"fake-tenant-id": {
"networks": [
mock.Mock()
],
},
},
"networking_agents": [{
"host": "fake-host",
"alive": True,
"admin_state_up": True,
"agent_type": "Open vSwitch agent",
}],
}
scenario = network.CreateAndBindPorts(context)
scenario._create_network = mock.Mock()
scenario._create_subnet = mock.Mock()
scenario._create_port = mock.Mock(
side_effect=ports)
scenario._update_port = mock.Mock()
scenario.run(
ports_per_network=ports_per_network)
scenario._update_port.assert_has_calls(
[mock.call(p, port_update_args=port_update_args) for p in ports])
def test_create_and_show_ports_positive(self):
port_create_args = {"allocation_pools": []}
ports_per_network = 1