Merge "Add full-stack test"
This commit is contained in:
commit
86669de211
|
@ -144,14 +144,19 @@ class PortFixture(fixtures.Fixture):
|
|||
class OVSBridgeFixture(fixtures.Fixture):
|
||||
"""Create an OVS bridge.
|
||||
|
||||
:ivar prefix: bridge name prefix
|
||||
:type prefix: str
|
||||
:ivar bridge: created bridge
|
||||
:type bridge: OVSBridge
|
||||
"""
|
||||
|
||||
def __init__(self, prefix=BR_PREFIX):
|
||||
self.prefix = prefix
|
||||
|
||||
def setUp(self):
|
||||
super(OVSBridgeFixture, self).setUp()
|
||||
ovs = ovs_lib.BaseOVS()
|
||||
self.bridge = common_base.create_resource(BR_PREFIX, ovs.add_bridge)
|
||||
self.bridge = common_base.create_resource(self.prefix, ovs.add_bridge)
|
||||
self.addCleanup(self.bridge.destroy)
|
||||
|
||||
|
||||
|
|
|
@ -21,23 +21,21 @@ from neutron.tests.fullstack import fullstack_fixtures as f_fixtures
|
|||
|
||||
|
||||
class BaseFullStackTestCase(test_base.MySQLOpportunisticTestCase):
|
||||
"""Base test class for full-stack tests.
|
||||
"""Base test class for full-stack tests."""
|
||||
|
||||
:param process_fixtures: a list of fixture classes (not instances).
|
||||
"""
|
||||
def __init__(self, environment=None, *args, **kwargs):
|
||||
super(BaseFullStackTestCase, self).__init__(*args, **kwargs)
|
||||
self.environment = (environment if environment
|
||||
else f_fixtures.EnvironmentFixture())
|
||||
|
||||
def setUp(self):
|
||||
super(BaseFullStackTestCase, self).setUp()
|
||||
self.create_db_tables()
|
||||
|
||||
self.neutron_server = self.useFixture(
|
||||
f_fixtures.NeutronServerFixture())
|
||||
self.client = self.neutron_server.client
|
||||
if self.environment:
|
||||
self.useFixture(self.environment)
|
||||
|
||||
@property
|
||||
def test_name(self):
|
||||
"""Return the name of the test currently running."""
|
||||
return self.id().split(".")[-1]
|
||||
self.client = self.environment.neutron_server.client
|
||||
|
||||
def create_db_tables(self):
|
||||
"""Populate the new database.
|
||||
|
|
|
@ -105,12 +105,15 @@ class NeutronConfigFixture(ConfigFixture):
|
|||
'DEFAULT': {
|
||||
'host': self._generate_host(),
|
||||
'state_path': self._generate_state_path(temp_dir),
|
||||
'lock_path': '$state_path/lock',
|
||||
'bind_port': self._generate_port(),
|
||||
'api_paste_config': self._generate_api_paste(),
|
||||
'policy_file': self._generate_policy_json(),
|
||||
'core_plugin': 'neutron.plugins.ml2.plugin.Ml2Plugin',
|
||||
'service_plugins': ('neutron.services.l3_router.'
|
||||
'l3_router_plugin.L3RouterPlugin'),
|
||||
'rabbit_userid': 'stackrabbit',
|
||||
'rabbit_password': 'secretrabbit',
|
||||
'rabbit_password': '127.0.0.1',
|
||||
'rabbit_hosts': '127.0.0.1',
|
||||
'auth_strategy': 'noauth',
|
||||
'verbose': 'True',
|
||||
|
@ -169,6 +172,10 @@ class ML2ConfigFixture(ConfigFixture):
|
|||
'local_ip': '127.0.0.1',
|
||||
'bridge_mappings': self._generate_bridge_mappings(),
|
||||
'integration_bridge': self._generate_integration_bridge(),
|
||||
},
|
||||
'securitygroup': {
|
||||
'firewall_driver': ('neutron.agent.linux.iptables_firewall.'
|
||||
'OVSHybridIptablesFirewallDriver'),
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -181,3 +188,28 @@ class ML2ConfigFixture(ConfigFixture):
|
|||
def _generate_integration_bridge(self):
|
||||
return base.get_rand_name(prefix='br-int',
|
||||
max_length=constants.DEVICE_NAME_MAX_LEN)
|
||||
|
||||
|
||||
class L3ConfigFixture(ConfigFixture):
|
||||
|
||||
def __init__(self, temp_dir, integration_bridge):
|
||||
super(L3ConfigFixture, self).__init__(
|
||||
temp_dir, base_filename='l3_agent.ini')
|
||||
|
||||
self.config.update({
|
||||
'DEFAULT': {
|
||||
'l3_agent_manager': ('neutron.agent.l3_agent.'
|
||||
'L3NATAgentWithStateReport'),
|
||||
'interface_driver': ('neutron.agent.linux.interface.'
|
||||
'OVSInterfaceDriver'),
|
||||
'ovs_integration_bridge': integration_bridge,
|
||||
'external_network_bridge': self._generate_external_bridge(),
|
||||
'router_delete_namespaces': 'True',
|
||||
'debug': 'True',
|
||||
'verbose': 'True',
|
||||
}
|
||||
})
|
||||
|
||||
def _generate_external_bridge(self):
|
||||
return base.get_rand_name(prefix='br-ex',
|
||||
max_length=constants.DEVICE_NAME_MAX_LEN)
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
# under the License.
|
||||
|
||||
from distutils import spawn
|
||||
import functools
|
||||
|
||||
import fixtures
|
||||
from neutronclient.common import exceptions as nc_exc
|
||||
|
@ -23,6 +24,7 @@ from oslo_utils import timeutils
|
|||
|
||||
from neutron.agent.linux import async_process
|
||||
from neutron.agent.linux import utils
|
||||
from neutron.tests.common import net_helpers
|
||||
from neutron.tests.fullstack import config_fixtures
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
@ -33,7 +35,6 @@ DEFAULT_LOG_DIR = '/opt/stack/logs'
|
|||
|
||||
class ProcessFixture(fixtures.Fixture):
|
||||
def __init__(self, name, exec_name, config_filenames):
|
||||
super(ProcessFixture, self).__init__()
|
||||
self.name = name
|
||||
self.exec_name = exec_name
|
||||
self.config_filenames = config_filenames
|
||||
|
@ -61,11 +62,39 @@ class ProcessFixture(fixtures.Fixture):
|
|||
super(ProcessFixture, self, *args, **kwargs)
|
||||
|
||||
|
||||
class EnvironmentFixture(fixtures.Fixture):
|
||||
|
||||
def setUp(self):
|
||||
super(EnvironmentFixture, self).setUp()
|
||||
|
||||
self.temp_dir = self.useFixture(fixtures.TempDir()).path
|
||||
|
||||
self.neutron_server = self.useFixture(
|
||||
NeutronServerFixture(self.temp_dir))
|
||||
|
||||
def wait_until_env_is_up(self, agents_count=0):
|
||||
utils.wait_until_true(
|
||||
functools.partial(self._processes_are_ready, agents_count))
|
||||
|
||||
def _processes_are_ready(self, agents_count):
|
||||
try:
|
||||
running_agents = self.neutron_server.client.list_agents()['agents']
|
||||
LOG.warn("There are %d agents running!", len(running_agents))
|
||||
return len(running_agents) == agents_count
|
||||
except nc_exc.NeutronClientException:
|
||||
LOG.warn("neutron-server isn't up yet (cannot contact REST API).")
|
||||
return False
|
||||
|
||||
|
||||
class NeutronServerFixture(fixtures.Fixture):
|
||||
|
||||
NEUTRON_SERVER = "neutron-server"
|
||||
|
||||
def __init__(self, temp_dir):
|
||||
self.temp_dir = temp_dir
|
||||
|
||||
def setUp(self):
|
||||
super(NeutronServerFixture, self).setUp()
|
||||
self.temp_dir = self.useFixture(fixtures.TempDir()).path
|
||||
|
||||
self.neutron_cfg_fixture = config_fixtures.NeutronConfigFixture(
|
||||
self.temp_dir, cfg.CONF.database.connection)
|
||||
|
@ -76,29 +105,91 @@ class NeutronServerFixture(fixtures.Fixture):
|
|||
self.useFixture(self.plugin_cfg_fixture)
|
||||
|
||||
self.neutron_config = self.neutron_cfg_fixture.config
|
||||
self.plugin_config = self.plugin_cfg_fixture.config
|
||||
|
||||
config_filenames = [self.neutron_cfg_fixture.filename,
|
||||
self.plugin_cfg_fixture.filename]
|
||||
|
||||
self.process_fixture = self.useFixture(ProcessFixture(
|
||||
name='neutron_server',
|
||||
exec_name='neutron-server',
|
||||
config_filenames=config_filenames,
|
||||
))
|
||||
name=self.NEUTRON_SERVER,
|
||||
exec_name=self.NEUTRON_SERVER,
|
||||
config_filenames=config_filenames))
|
||||
|
||||
utils.wait_until_true(self.processes_are_ready)
|
||||
utils.wait_until_true(self.server_is_live)
|
||||
|
||||
def server_is_live(self):
|
||||
try:
|
||||
self.client.list_networks()
|
||||
return True
|
||||
except nc_exc.NeutronClientException:
|
||||
LOG.warn("neutron-server isn't up yet (cannot contact REST API).")
|
||||
return False
|
||||
|
||||
@property
|
||||
def client(self):
|
||||
url = "http://127.0.0.1:%s" % self.neutron_config.DEFAULT.bind_port
|
||||
return client.Client(auth_strategy="noauth", endpoint_url=url)
|
||||
|
||||
def processes_are_ready(self):
|
||||
# ProcessFixture will ensure that the server has started, but
|
||||
# that doesn't mean that the server will be serving commands yet, nor
|
||||
# that all processes are up.
|
||||
try:
|
||||
return len(self.client.list_agents()['agents']) == 0
|
||||
except nc_exc.NeutronClientException:
|
||||
LOG.debug("Processes aren't up yet.")
|
||||
return False
|
||||
|
||||
class OVSAgentFixture(fixtures.Fixture):
|
||||
|
||||
NEUTRON_OVS_AGENT = "neutron-openvswitch-agent"
|
||||
|
||||
def __init__(self, neutron_cfg_fixture, ml2_cfg_fixture):
|
||||
self.neutron_cfg_fixture = neutron_cfg_fixture
|
||||
self.plugin_cfg_fixture = ml2_cfg_fixture
|
||||
|
||||
self.neutron_config = self.neutron_cfg_fixture.config
|
||||
self.plugin_config = self.plugin_cfg_fixture.config
|
||||
|
||||
def setUp(self):
|
||||
super(OVSAgentFixture, self).setUp()
|
||||
|
||||
self.useFixture(net_helpers.OVSBridgeFixture(self._get_br_int_name()))
|
||||
self.useFixture(net_helpers.OVSBridgeFixture(self._get_br_phys_name()))
|
||||
|
||||
config_filenames = [self.neutron_cfg_fixture.filename,
|
||||
self.plugin_cfg_fixture.filename]
|
||||
|
||||
self.process_fixture = self.useFixture(ProcessFixture(
|
||||
name=self.NEUTRON_OVS_AGENT,
|
||||
exec_name=self.NEUTRON_OVS_AGENT,
|
||||
config_filenames=config_filenames))
|
||||
|
||||
def _get_br_int_name(self):
|
||||
return self.plugin_config.ovs.integration_bridge
|
||||
|
||||
def _get_br_phys_name(self):
|
||||
return self.plugin_config.ovs.bridge_mappings.split(':')[1]
|
||||
|
||||
|
||||
class L3AgentFixture(fixtures.Fixture):
|
||||
|
||||
NEUTRON_L3_AGENT = "neutron-l3-agent"
|
||||
|
||||
def __init__(self, temp_dir, neutron_cfg_fixture, integration_bridge_name):
|
||||
self.temp_dir = temp_dir
|
||||
self.neutron_cfg_fixture = neutron_cfg_fixture
|
||||
self.neutron_config = self.neutron_cfg_fixture.config
|
||||
self.integration_bridge_name = integration_bridge_name
|
||||
|
||||
def setUp(self):
|
||||
super(L3AgentFixture, self).setUp()
|
||||
|
||||
self.plugin_cfg_fixture = config_fixtures.L3ConfigFixture(
|
||||
self.temp_dir, self.integration_bridge_name)
|
||||
self.useFixture(self.plugin_cfg_fixture)
|
||||
self.plugin_config = self.plugin_cfg_fixture.config
|
||||
|
||||
self.useFixture(net_helpers.OVSBridgeFixture(self._get_br_ex_name()))
|
||||
|
||||
config_filenames = [self.neutron_cfg_fixture.filename,
|
||||
self.plugin_cfg_fixture.filename]
|
||||
|
||||
self.process_fixture = self.useFixture(ProcessFixture(
|
||||
name=self.NEUTRON_L3_AGENT,
|
||||
exec_name=self.NEUTRON_L3_AGENT,
|
||||
config_filenames=config_filenames))
|
||||
|
||||
def _get_br_ex_name(self):
|
||||
return self.plugin_config.DEFAULT.external_network_bridge
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
# Copyright 2015 Red Hat, Inc.
|
||||
#
|
||||
# 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 neutron.agent.l3 import agent as l3_agent
|
||||
from neutron.agent.linux import ip_lib
|
||||
from neutron.agent.linux import utils
|
||||
from neutron.openstack.common import uuidutils
|
||||
from neutron.tests.fullstack import base
|
||||
from neutron.tests.fullstack import fullstack_fixtures as f_fixtures
|
||||
|
||||
|
||||
class SingleNodeEnvironment(f_fixtures.EnvironmentFixture):
|
||||
def setUp(self):
|
||||
super(SingleNodeEnvironment, self).setUp()
|
||||
|
||||
neutron_config = self.neutron_server.neutron_cfg_fixture
|
||||
ml2_config = self.neutron_server.plugin_cfg_fixture
|
||||
|
||||
self.ovs_agent = self.useFixture(
|
||||
f_fixtures.OVSAgentFixture(
|
||||
neutron_config, ml2_config))
|
||||
|
||||
self.l3_agent = self.useFixture(
|
||||
f_fixtures.L3AgentFixture(
|
||||
self.temp_dir,
|
||||
neutron_config,
|
||||
self.ovs_agent._get_br_int_name()))
|
||||
|
||||
self.wait_until_env_is_up(agents_count=2)
|
||||
|
||||
|
||||
class TestLegacyL3Agent(base.BaseFullStackTestCase):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(TestLegacyL3Agent, self).__init__(
|
||||
SingleNodeEnvironment(), *args, **kwargs)
|
||||
|
||||
def _get_namespace(self, router_id):
|
||||
return "%s%s" % (l3_agent.NS_PREFIX, router_id)
|
||||
|
||||
def _assert_namespace_exists(self, ns_name):
|
||||
ip = ip_lib.IPWrapper(ns_name)
|
||||
utils.wait_until_true(lambda: ip.netns.exists(ns_name))
|
||||
|
||||
def test_namespace_exists(self):
|
||||
uuid = uuidutils.generate_uuid()
|
||||
|
||||
router = self.client.create_router(
|
||||
body={'router': {'name': 'router-test',
|
||||
'tenant_id': uuid}})
|
||||
|
||||
network = self.client.create_network(
|
||||
body={'network': {'name': 'network-test',
|
||||
'tenant_id': uuid}})
|
||||
|
||||
subnet = self.client.create_subnet(
|
||||
body={'subnet': {'name': 'subnet-test',
|
||||
'tenant_id': uuid,
|
||||
'network_id': network['network']['id'],
|
||||
'cidr': '20.0.0.0/24',
|
||||
'gateway_ip': '20.0.0.1',
|
||||
'ip_version': 4,
|
||||
'enable_dhcp': True}})
|
||||
|
||||
self.client.add_interface_router(
|
||||
router=router['router']['id'],
|
||||
body={'subnet_id': subnet['subnet']['id']})
|
||||
|
||||
router_id = router['router']['id']
|
||||
self._assert_namespace_exists(self._get_namespace(router_id))
|
||||
|
||||
self.client.remove_interface_router(
|
||||
router=router['router']['id'],
|
||||
body={'subnet_id': subnet['subnet']['id']})
|
||||
|
||||
self.client.delete_subnet(subnet['subnet']['id'])
|
||||
self.client.delete_network(network['network']['id'])
|
||||
self.client.delete_router(router['router']['id'])
|
|
@ -1,25 +0,0 @@
|
|||
# Copyright 2015 Red Hat, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
#TODO(jschwarz): This is an example test file which demonstrates the
|
||||
# general usage of fullstack. Once we add more FullStack tests, this should
|
||||
# be deleted.
|
||||
|
||||
from neutron.tests.fullstack import base
|
||||
|
||||
|
||||
class TestSanity(base.BaseFullStackTestCase):
|
||||
|
||||
def test_sanity(self):
|
||||
self.assertEqual(self.client.list_networks(), {'networks': []})
|
Loading…
Reference in New Issue