Merge "Allow to configure max vlans for trunk port tests"
diff --git a/.zuul.yaml b/.zuul.yaml
index 45ef47a..ba7e158 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -52,11 +52,46 @@
- ^setup.cfg$
voting: false
+- job:
+ name: neutron-tempest-plugin-designate-scenario
+ parent: devstack-tempest
+ description: Neutron designate integration scenario
+ required-projects:
+ - openstack/designate
+ - openstack/designate-dashboard
+ - openstack/designate-tempest-plugin
+ - openstack/neutron
+ - openstack/neutron-tempest-plugin
+ - openstack/tempest
+ timeout: 3600
+ roles:
+ - zuul: openstack-dev/devstack
+ vars:
+ devstack_localrc:
+ DESIGNATE_BACKEND_DRIVER: bind9
+ devstack_plugins:
+ designate: git://git.openstack.org/openstack/designate.git
+ neutron: git://git.openstack.org/openstack/neutron.git
+ neutron-tempest-plugin: git://git.openstack.org/openstack/neutron-tempest-plugin.git
+ devstack_services:
+ cinder: False
+ designate: True
+ q-dns: True
+ tempest: True
+ tempest_test_regex: '^neutron_tempest_plugin\.scenario\.test_dns_integration'
+ tox_venvlist: all-plugin
+ irrelevant-files:
+ - ^(test-|)requirements.txt$
+ - ^releasenotes/.*$
+ - ^setup.cfg$
+ voting: false
+
- project-template:
name: neutron-tempest-plugin-jobs
check:
jobs:
- neutron-tempest-plugin-api
+ - neutron-tempest-plugin-designate-scenario
- neutron-tempest-plugin-dvr-multinode-scenario
- neutron-tempest-plugin-scenario-linuxbridge
gate:
diff --git a/neutron_tempest_plugin/api/base.py b/neutron_tempest_plugin/api/base.py
index ec66818..68b5680 100644
--- a/neutron_tempest_plugin/api/base.py
+++ b/neutron_tempest_plugin/api/base.py
@@ -69,6 +69,9 @@
force_new=force_new
)
# Neutron uses a different clients manager than the one in the Tempest
+ # save the original in case mixed tests need it
+ if credential_type == 'primary':
+ cls.os_tempest = manager
return clients.Manager(manager.credentials)
@classmethod
diff --git a/neutron_tempest_plugin/api/test_trunk.py b/neutron_tempest_plugin/api/test_trunk.py
index 6c781ab..e02cf92 100644
--- a/neutron_tempest_plugin/api/test_trunk.py
+++ b/neutron_tempest_plugin/api/test_trunk.py
@@ -54,8 +54,20 @@
trunks_cleanup(cls.client, cls.trunks)
super(TrunkTestJSONBase, cls).resource_cleanup()
- def _create_trunk_with_network_and_parent(self, subports, **kwargs):
- network = self.create_network()
+ @classmethod
+ def is_type_driver_enabled(cls, type_driver):
+ return (type_driver in
+ config.CONF.neutron_plugin_options.available_type_drivers)
+
+ def _create_trunk_with_network_and_parent(
+ self, subports, parent_network_type=None, **kwargs):
+ client = None
+ network_kwargs = {}
+ if parent_network_type:
+ client = self.admin_client
+ network_kwargs = {"provider:network_type": parent_network_type,
+ "tenant_id": self.client.tenant_id}
+ network = self.create_network(client=client, **network_kwargs)
parent_port = self.create_port(network)
trunk = self.client.create_trunk(parent_port['id'], subports, **kwargs)
self.trunks.append(trunk['trunk'])
@@ -266,9 +278,7 @@
@classmethod
def skip_checks(cls):
super(TrunkTestMtusJSONBase, cls).skip_checks()
- if any(t
- not in config.CONF.neutron_plugin_options.available_type_drivers
- for t in ['gre', 'vxlan']):
+ if not all(cls.is_type_driver_enabled(t) for t in ['gre', 'vxlan']):
msg = "Either vxlan or gre type driver not enabled."
raise cls.skipException(msg)
diff --git a/neutron_tempest_plugin/api/test_trunk_negative.py b/neutron_tempest_plugin/api/test_trunk_negative.py
index 699b26f..4d7ead1 100644
--- a/neutron_tempest_plugin/api/test_trunk_negative.py
+++ b/neutron_tempest_plugin/api/test_trunk_negative.py
@@ -13,6 +13,7 @@
# under the License.
from oslo_utils import uuidutils
+from tempest.common import utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
import testtools
@@ -103,8 +104,14 @@
@decorators.attr(type='negative')
@decorators.idempotent_id('40aed9be-e976-47d0-dada-bde2c7e74e57')
+ @utils.requires_ext(extension="provider", service="network")
def test_create_subport_invalid_inherit_network_segmentation_type(self):
- trunk = self._create_trunk_with_network_and_parent([])
+ if not self.is_type_driver_enabled('vxlan'):
+ msg = "Vxlan type driver must be enabled for this test."
+ raise self.skipException(msg)
+
+ trunk = self._create_trunk_with_network_and_parent(
+ subports=[], parent_network_type='vxlan')
subport_network = self.create_network()
parent_port = self.create_port(subport_network)
self.assertRaises(lib_exc.BadRequest, self.client.add_subports,
diff --git a/neutron_tempest_plugin/scenario/test_dns_integration.py b/neutron_tempest_plugin/scenario/test_dns_integration.py
new file mode 100644
index 0000000..923f013
--- /dev/null
+++ b/neutron_tempest_plugin/scenario/test_dns_integration.py
@@ -0,0 +1,123 @@
+# Copyright (c) 2017 x-ion GmbH
+# All Rights Reserved.
+#
+# 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 ipaddress
+
+import testtools
+
+from tempest.common import utils
+from tempest.common import waiters
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+
+from neutron_tempest_plugin import config
+from neutron_tempest_plugin.scenario import base
+from neutron_tempest_plugin.scenario import constants
+
+
+CONF = config.CONF
+
+# Note(jh): Need to do a bit of juggling here in order to avoid failures
+# when designate_tempest_plugin is not available
+dns_base = testtools.try_import('designate_tempest_plugin.tests.base')
+dns_waiters = testtools.try_import('designate_tempest_plugin.common.waiters')
+if dns_base:
+ DNSMixin = dns_base.BaseDnsV2Test
+else:
+ DNSMixin = object
+
+
+class DNSIntegrationTests(base.BaseTempestTestCase, DNSMixin):
+ credentials = ['primary']
+
+ @classmethod
+ def setup_clients(cls):
+ super(DNSIntegrationTests, cls).setup_clients()
+ cls.dns_client = cls.os_tempest.zones_client
+ cls.query_client = cls.os_tempest.query_client
+ cls.query_client.build_timeout = 30
+
+ @classmethod
+ def skip_checks(cls):
+ super(DNSIntegrationTests, cls).skip_checks()
+ if not ('designate' in CONF.service_available and
+ CONF.service_available.designate):
+ raise cls.skipException("Designate support is required")
+ if not (dns_base and dns_waiters):
+ raise cls.skipException("Designate tempest plugin is missing")
+
+ @classmethod
+ @utils.requires_ext(extension="dns-integration", service="network")
+ def resource_setup(cls):
+ super(DNSIntegrationTests, cls).resource_setup()
+ _, cls.zone = cls.dns_client.create_zone()
+ cls.addClassResourceCleanup(cls.dns_client.delete_zone,
+ cls.zone['id'], ignore_errors=lib_exc.NotFound)
+ dns_waiters.wait_for_zone_status(
+ cls.dns_client, cls.zone['id'], 'ACTIVE')
+
+ cls.network = cls.create_network(dns_domain=cls.zone['name'])
+ cls.subnet = cls.create_subnet(cls.network)
+ cls.router = cls.create_router_by_client()
+ cls.create_router_interface(cls.router['id'], cls.subnet['id'])
+ cls.keypair = cls.create_keypair()
+
+ def _create_floatingip_with_dns(self, dns_name):
+ fip = self.os_primary.network_client.create_floatingip(
+ CONF.network.public_network_id, dns_name=dns_name,
+ dns_domain=self.zone['name'])['floatingip']
+ self.floating_ips.append(fip)
+ return fip
+
+ def _create_server(self, name=None):
+ port = self.create_port(self.network)
+ server = self.create_server(
+ flavor_ref=CONF.compute.flavor_ref,
+ image_ref=CONF.compute.image_ref,
+ key_name=self.keypair['name'], name=name,
+ networks=[{'port': port['id']}])['server']
+ waiters.wait_for_server_status(self.os_primary.servers_client,
+ server['id'],
+ constants.SERVER_STATUS_ACTIVE)
+ fip = self.create_and_associate_floatingip(port['id'])
+ return {'port': port, 'fip': fip, 'server': server}
+
+ def _verify_dns_records(self, address, name):
+ forward = name + '.' + self.zone['name']
+ reverse = ipaddress.ip_address(address).reverse_pointer
+ dns_waiters.wait_for_query(self.query_client, forward, 'A')
+ dns_waiters.wait_for_query(self.query_client, reverse, 'PTR')
+ fwd_response = self.query_client.query(forward, 'A')
+ rev_response = self.query_client.query(reverse, 'PTR')
+ for r in fwd_response:
+ for rr in r.answer:
+ self.assertIn(address, rr.to_text())
+ for r in rev_response:
+ for rr in r.answer:
+ self.assertIn(forward, rr.to_text())
+
+ @decorators.idempotent_id('850ee378-4b5a-4f71-960e-0e7b12e03a34')
+ def test_server_with_fip(self):
+ name = data_utils.rand_name('server-test')
+ server = self._create_server(name=name)
+ server_ip = server['fip']['floating_ip_address']
+ self._verify_dns_records(server_ip, name)
+
+ @decorators.idempotent_id('a8f2fade-8d5c-40f9-80f0-3de4b8d91985')
+ def test_fip(self):
+ name = data_utils.rand_name('fip-test')
+ fip = self._create_floatingip_with_dns(name)
+ self._verify_dns_records(fip['floating_ip_address'], name)
diff --git a/neutron_tempest_plugin/scenario/test_security_groups.py b/neutron_tempest_plugin/scenario/test_security_groups.py
index 1244535..9503fe3 100644
--- a/neutron_tempest_plugin/scenario/test_security_groups.py
+++ b/neutron_tempest_plugin/scenario/test_security_groups.py
@@ -26,13 +26,13 @@
CONF = config.CONF
-class NetworkDefaultSecGroupTest(base.BaseTempestTestCase):
+class NetworkSecGroupTest(base.BaseTempestTestCase):
credentials = ['primary', 'admin']
required_extensions = ['router', 'security-group']
@classmethod
def resource_setup(cls):
- super(NetworkDefaultSecGroupTest, cls).resource_setup()
+ super(NetworkSecGroupTest, cls).resource_setup()
# setup basic topology for servers we can log into it
cls.network = cls.create_network()
cls.subnet = cls.create_subnet(cls.network)
@@ -40,15 +40,26 @@
cls.create_router_interface(router['id'], cls.subnet['id'])
cls.keypair = cls.create_keypair()
- def create_vm_testing_sec_grp(self, num_servers=2, security_groups=None):
+ def create_vm_testing_sec_grp(self, num_servers=2, security_groups=None,
+ ports=None):
+ """Create instance for security group testing
+ :param num_servers (int): number of servers to spawn
+ :param security_groups (list): list of security groups
+ :param ports* (list): list of ports
+ *Needs to be the same length as num_servers
+ """
servers, fips, server_ssh_clients = ([], [], [])
for i in range(num_servers):
- servers.append(self.create_server(
- flavor_ref=CONF.compute.flavor_ref,
- image_ref=CONF.compute.image_ref,
- key_name=self.keypair['name'],
- networks=[{'uuid': self.network['id']}],
- security_groups=security_groups))
+ server_args = {
+ 'flavor_ref': CONF.compute.flavor_ref,
+ 'image_ref': CONF.compute.image_ref,
+ 'key_name': self.keypair['name'],
+ 'networks': [{'uuid': self.network['id']}],
+ 'security_groups': security_groups
+ }
+ if ports is not None:
+ server_args['networks'][0].update({'port': ports[i]['id']})
+ servers.append(self.create_server(**server_args))
for i, server in enumerate(servers):
waiters.wait_for_server_status(
self.os_primary.servers_client, server['server']['id'],
@@ -210,3 +221,70 @@
'direction': constants.INGRESS_DIRECTION,
'remote_ip_prefix': cidr}]
self._test_ip_prefix(rule_list, should_succeed=False)
+
+ @decorators.idempotent_id('7ed39b86-006d-40fb-887a-ae46693dabc9')
+ def test_remote_group(self):
+ # create a new sec group
+ ssh_secgrp_name = data_utils.rand_name('ssh_secgrp')
+ ssh_secgrp = self.os_primary.network_client.create_security_group(
+ name=ssh_secgrp_name)
+ # add cleanup
+ self.security_groups.append(ssh_secgrp['security_group'])
+ # configure sec group to support SSH connectivity
+ self.create_loginable_secgroup_rule(
+ secgroup_id=ssh_secgrp['security_group']['id'])
+ # spawn two instances with the sec group created
+ server_ssh_clients, fips, servers = self.create_vm_testing_sec_grp(
+ security_groups=[{'name': ssh_secgrp_name}])
+ # verify SSH functionality
+ for i in range(2):
+ self.check_connectivity(fips[i]['floating_ip_address'],
+ CONF.validation.image_ssh_user,
+ self.keypair['private_key'])
+ # try to ping instances without ICMP permissions
+ self.check_remote_connectivity(
+ server_ssh_clients[0], fips[1]['fixed_ip_address'],
+ should_succeed=False)
+ # add ICMP support to the remote group
+ rule_list = [{'protocol': constants.PROTO_NUM_ICMP,
+ 'direction': constants.INGRESS_DIRECTION,
+ 'remote_group_id': ssh_secgrp['security_group']['id']}]
+ self.create_secgroup_rules(
+ rule_list, secgroup_id=ssh_secgrp['security_group']['id'])
+ # verify ICMP connectivity between instances works
+ self.check_remote_connectivity(
+ server_ssh_clients[0], fips[1]['fixed_ip_address'])
+ # make sure ICMP connectivity doesn't work from framework
+ self.ping_ip_address(fips[0]['floating_ip_address'],
+ should_succeed=False)
+
+ @decorators.idempotent_id('f07d0159-8f9e-4faa-87f5-a869ab0ad488')
+ def test_multiple_ports_secgroup_inheritance(self):
+ """This test creates two ports with security groups, then
+ boots two instances and verify that the security group was
+ inherited properly and enforced in these instances.
+ """
+ # create a security group and make it loginable and pingable
+ secgrp = self.os_primary.network_client.create_security_group(
+ name=data_utils.rand_name('secgrp'))
+ self.create_loginable_secgroup_rule(
+ secgroup_id=secgrp['security_group']['id'])
+ self.create_pingable_secgroup_rule(
+ secgroup_id=secgrp['security_group']['id'])
+ # add security group to cleanup
+ self.security_groups.append(secgrp['security_group'])
+ # create two ports with fixed IPs and the security group created
+ ports = []
+ for i in range(2):
+ ports.append(self.create_port(
+ self.network, fixed_ips=[{'subnet_id': self.subnets[0]['id']}],
+ security_groups=[secgrp['security_group']['id']]))
+ # spawn instances with the ports created
+ server_ssh_clients, fips, servers = self.create_vm_testing_sec_grp(
+ ports=ports)
+ # verify ICMP reachability and ssh connectivity
+ for fip in fips:
+ self.ping_ip_address(fip['floating_ip_address'])
+ self.check_connectivity(fip['floating_ip_address'],
+ CONF.validation.image_ssh_user,
+ self.keypair['private_key'])
diff --git a/playbooks/neutron-tempest-plugin-dvr-multinode-scenario/run.yaml b/playbooks/neutron-tempest-plugin-dvr-multinode-scenario/run.yaml
index c2d33a9..2102bb5 100644
--- a/playbooks/neutron-tempest-plugin-dvr-multinode-scenario/run.yaml
+++ b/playbooks/neutron-tempest-plugin-dvr-multinode-scenario/run.yaml
@@ -1,4 +1,4 @@
-- hosts: all
+- hosts: primary
name: neutron-tempest-plugin-dvr-multinode-scenario
tasks:
diff --git a/requirements.txt b/requirements.txt
index 84ee391..e546885 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -5,6 +5,7 @@
pbr>=2.0 # Apache-2.0
neutron-lib>=1.9.0 # Apache-2.0
oslo.config!=4.3.0,!=4.4.0,>=4.0.0 # Apache-2.0
+ipaddress>=1.0.16;python_version<'3.3' # PSF
netaddr!=0.7.16,>=0.7.13 # BSD
oslo.log>=3.22.0 # Apache-2.0
oslo.serialization!=2.19.1,>=1.10.0 # Apache-2.0