From: John Schwarz Date: Tue, 14 Oct 2014 11:12:35 +0000 (+0300) Subject: Add full-stack test X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=304d68d9741fd15c14263d978e5b0bae43cde58e;p=openstack-build%2Fneutron-build.git Add full-stack test Currently, the full-stack framework has only one test which only uses the neutron-server. This patch adds an actual test which makes sure that once a router is created, an actual namespace is create for it. Since this test requires 3 processes (neutron-server, l3-agent, ovs-agent), existing full-stack code is modified to add more streamlined support for such code. Partially-Implements: blueprint integration-tests Change-Id: Id5a8852d38543590b90e4bbed261a7a458071a9a --- diff --git a/neutron/tests/common/net_helpers.py b/neutron/tests/common/net_helpers.py index 4ccf06d20..3a1fdc513 100644 --- a/neutron/tests/common/net_helpers.py +++ b/neutron/tests/common/net_helpers.py @@ -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) diff --git a/neutron/tests/fullstack/base.py b/neutron/tests/fullstack/base.py index a69cc989b..1a50acb74 100644 --- a/neutron/tests/fullstack/base.py +++ b/neutron/tests/fullstack/base.py @@ -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. diff --git a/neutron/tests/fullstack/config_fixtures.py b/neutron/tests/fullstack/config_fixtures.py index 8767867c4..6c25c9655 100644 --- a/neutron/tests/fullstack/config_fixtures.py +++ b/neutron/tests/fullstack/config_fixtures.py @@ -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) diff --git a/neutron/tests/fullstack/fullstack_fixtures.py b/neutron/tests/fullstack/fullstack_fixtures.py index 9feed50d6..fc2ab0bc8 100644 --- a/neutron/tests/fullstack/fullstack_fixtures.py +++ b/neutron/tests/fullstack/fullstack_fixtures.py @@ -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 diff --git a/neutron/tests/fullstack/test_l3_agent.py b/neutron/tests/fullstack/test_l3_agent.py new file mode 100644 index 000000000..b527d064e --- /dev/null +++ b/neutron/tests/fullstack/test_l3_agent.py @@ -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']) diff --git a/neutron/tests/fullstack/test_sanity.py b/neutron/tests/fullstack/test_sanity.py deleted file mode 100644 index 6fc912995..000000000 --- a/neutron/tests/fullstack/test_sanity.py +++ /dev/null @@ -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': []})