Merge "Refactoring - Use existing Tempest APIs in "QoS bandwidth limit rule" tests"
diff --git a/neutron_tempest_plugin/scenario/test_ipv6.py b/neutron_tempest_plugin/scenario/test_ipv6.py
index 32fb581..d9d1a22 100644
--- a/neutron_tempest_plugin/scenario/test_ipv6.py
+++ b/neutron_tempest_plugin/scenario/test_ipv6.py
@@ -20,6 +20,7 @@
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
+import testtools
from neutron_tempest_plugin.common import ip
from neutron_tempest_plugin.common import ssh
@@ -87,6 +88,12 @@
ipv6_address_mode = 'slaac'
@classmethod
+ def skip_checks(cls):
+ super(IPv6Test, cls).skip_checks()
+ if not CONF.network_feature_enabled.ipv6:
+ raise cls.skipException("IPv6 is not enabled")
+
+ @classmethod
@tempest_utils.requires_ext(extension="router", service="network")
def resource_setup(cls):
super(IPv6Test, cls).resource_setup()
@@ -180,10 +187,14 @@
ssh_client=ssh_client, mac_address=ipv6_port['mac_address'])
self._test_ipv6_address_configured(ssh_client, vm, ipv6_port)
+ @testtools.skipUnless(CONF.network_feature_enabled.ipv6_subnet_attributes,
+ "DHCPv6 attributes are not enabled.")
@decorators.idempotent_id('b13e5408-5250-4a42-8e46-6996ce613e91')
def test_ipv6_hotplug_slaac(self):
self._test_ipv6_hotplug("slaac", "slaac")
+ @testtools.skipUnless(CONF.network_feature_enabled.ipv6_subnet_attributes,
+ "DHCPv6 attributes are not enabled.")
@decorators.idempotent_id('9aaedbc4-986d-42d5-9177-3e721728e7e0')
def test_ipv6_hotplug_dhcpv6stateless(self):
self._test_ipv6_hotplug("dhcpv6-stateless", "dhcpv6-stateless")
diff --git a/neutron_tempest_plugin/tap_as_a_service/__init__.py b/neutron_tempest_plugin/tap_as_a_service/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/neutron_tempest_plugin/tap_as_a_service/__init__.py
diff --git a/neutron_tempest_plugin/tap_as_a_service/api/__init__.py b/neutron_tempest_plugin/tap_as_a_service/api/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/neutron_tempest_plugin/tap_as_a_service/api/__init__.py
diff --git a/neutron_tempest_plugin/tap_as_a_service/api/test_taas.py b/neutron_tempest_plugin/tap_as_a_service/api/test_taas.py
new file mode 100644
index 0000000..06dce53
--- /dev/null
+++ b/neutron_tempest_plugin/tap_as_a_service/api/test_taas.py
@@ -0,0 +1,129 @@
+# 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 tempest.common import utils
+from tempest import config
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+
+from neutron_tempest_plugin.tap_as_a_service import base
+
+CONF = config.CONF
+
+
+class TaaSExtensionTestJSON(base.BaseTaasTest):
+
+ @classmethod
+ @utils.requires_ext(extension='taas', service='network')
+ def skip_checks(cls):
+ super(TaaSExtensionTestJSON, cls).skip_checks()
+
+ @classmethod
+ def resource_setup(cls):
+ super(TaaSExtensionTestJSON, cls).resource_setup()
+ cls.network = cls.create_network()
+ cls.ts_port = cls.create_port(cls.network)
+ cls.tf_port = cls.create_port(cls.network)
+ cls.tf2_port = cls.create_port(cls.network)
+
+ @decorators.idempotent_id('b993c14e-797a-4c91-b4da-8cb1a450aa2f')
+ def test_create_tap_service_and_flow(self):
+ """create tap service adn tap flow
+
+ Test create tap service and flow.
+ """
+ tap_service = self.create_tap_service(port_id=self.ts_port['id'])
+ self.create_tap_flow(tap_service_id=tap_service['id'],
+ direction='BOTH', source_port=self.tf_port['id'])
+
+ @decorators.idempotent_id('897a0aaf-1b55-4ea8-9d9f-1bc0fd09cb60')
+ @utils.requires_ext(extension='taas-vlan-filter', service='network')
+ def test_create_tap_service_and_flow_vlan_filter(self):
+ """create tap service with vlan_filter
+
+ Test create tap service with additional vlan_filter argument.
+ """
+ tap_service = self.create_tap_service(port_id=self.ts_port['id'])
+ tap_flow = self.create_tap_flow(tap_service_id=tap_service['id'],
+ direction='BOTH',
+ source_port=self.tf_port['id'],
+ vlan_filter='189,279,999-1008')
+ self.assertEqual(tap_flow['vlan_filter'], '189,279,999-1008')
+
+ @decorators.idempotent_id('d7a2115d-16b4-41cf-95a6-dcebc3682b24')
+ def test_delete_tap_resources_after_ts_port_delete(self):
+ """delete tap resources after ts port delete
+
+ Test delete tap resources after deletion of ts port.
+ """
+ tap_service = self.create_tap_service(port_id=self.ts_port['id'])
+ tap_flow = self.create_tap_flow(tap_service_id=tap_service['id'],
+ direction='BOTH',
+ source_port=self.tf2_port['id'])
+ # delete ts_port; it shall also delete the associated tap-service and
+ # subsequently the tap-flow as well
+ self.ports_client.delete_port(self.ts_port['id'])
+ # Attempt tap-service deletion; it should throw not found exception.
+ self.assertRaises(lib_exc.NotFound,
+ self.tap_services_client.delete_tap_service,
+ tap_service['id'])
+ # Attempt tap-flow deletion; it should throw not found exception.
+ self.assertRaises(lib_exc.NotFound,
+ self.tap_flows_client.delete_tap_flow,
+ tap_flow['id'])
+
+ @decorators.idempotent_id('9ba4edfd-4002-4c44-b02b-6c4f71b40a92')
+ def test_delete_tap_resources_after_tf_port_delete(self):
+ """delete tap resources after tf port delete
+
+ Test delete tap service after deletion of tf port.
+ """
+ tap_service = self.create_tap_service(port_id=self.ts_port['id'])
+ tap_flow = self.create_tap_flow(tap_service_id=tap_service['id'],
+ direction='BOTH',
+ source_port=self.tf_port['id'])
+ # delete tf port; it shall also delete the associated tap-flow
+ self.ports_client.delete_port(self.tf_port['id'])
+ # Attempt tap-flow deletion; it should throw not found exception.
+ self.assertRaises(lib_exc.NotFound,
+ self.tap_flows_client.delete_tap_flow,
+ tap_flow['id'])
+ # delete tap service; it shall go fine
+ self.tap_services_client.delete_tap_service(tap_service['id'])
+
+ @decorators.idempotent_id('687089b8-b045-496d-86bf-030b380039d1')
+ def test_create_and_update_tap_service(self):
+ """create and update tap service
+
+ Test update tap service - update description.
+ """
+ tap_service = self.create_tap_service(port_id=self.ts_port['id'])
+
+ # Update description of the tap service
+ self.update_tap_service(
+ tap_service['id'],
+ description='Tap Service Description Updated')
+
+ @decorators.idempotent_id('bb4d5482-37fc-46b5-85a5-5867e9adbfae')
+ def test_create_and_update_tap_flow(self):
+ """create and update tap flow
+
+ Test update tap flow - update description.
+ """
+ tap_service = self.create_tap_service(port_id=self.ts_port['id'])
+ tap_flow = self.create_tap_flow(
+ tap_service_id=tap_service['id'],
+ direction='BOTH', source_port=self.tf_port['id'])
+ # Update description of the tap flow
+ self.update_tap_flow(
+ tap_flow['id'],
+ description='Tap Flow Description Updated')
diff --git a/neutron_tempest_plugin/tap_as_a_service/base.py b/neutron_tempest_plugin/tap_as_a_service/base.py
new file mode 100644
index 0000000..3ddc797
--- /dev/null
+++ b/neutron_tempest_plugin/tap_as_a_service/base.py
@@ -0,0 +1,82 @@
+# 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 tempest.api.network.base as test
+from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
+
+from neutron_tempest_plugin.tap_as_a_service.services import taas_client
+
+CONF = config.CONF
+
+
+class BaseTaasTest(test.BaseAdminNetworkTest):
+
+ @classmethod
+ def resource_setup(cls):
+ super(BaseTaasTest, cls).resource_setup()
+ os_primary = cls.os_primary
+ cls.tap_services_client = taas_client.TapServicesClient(
+ os_primary.auth_provider,
+ CONF.network.catalog_type,
+ CONF.network.region or CONF.identity.region,
+ endpoint_type=CONF.network.endpoint_type,
+ build_interval=CONF.network.build_interval,
+ build_timeout=CONF.network.build_timeout,
+ **os_primary.default_params)
+ cls.tap_flows_client = taas_client.TapFlowsClient(
+ os_primary.auth_provider,
+ CONF.network.catalog_type,
+ CONF.network.region or CONF.identity.region,
+ endpoint_type=CONF.network.endpoint_type,
+ build_interval=CONF.network.build_interval,
+ build_timeout=CONF.network.build_timeout,
+ **os_primary.default_params)
+
+ def create_tap_service(self, **kwargs):
+ body = self.tap_services_client.create_tap_service(
+ name=data_utils.rand_name("tap_service"),
+ **kwargs)
+ tap_service = body['tap_service']
+ self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+ self.tap_services_client.delete_tap_service,
+ tap_service['id'])
+ return tap_service
+
+ def create_tap_flow(self, **kwargs):
+ body = self.tap_flows_client.create_tap_flow(
+ name=data_utils.rand_name("tap_service"),
+ **kwargs)
+ tap_flow = body['tap_flow']
+ self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+ self.tap_flows_client.delete_tap_flow,
+ tap_flow['id'])
+ return tap_flow
+
+ def update_tap_service(self, tap_service_id, **kwargs):
+ body = self.tap_services_client.update_tap_service(
+ tap_service_id,
+ **kwargs)
+ tap_service = body['tap_service']
+ self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+ self.tap_services_client.delete_tap_service,
+ tap_service['id'])
+
+ def update_tap_flow(self, tap_flow_id, **kwargs):
+ body = self.tap_flows_client.update_tap_flow(
+ tap_flow_id,
+ **kwargs)
+ tap_flow = body['tap_flow']
+ self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+ self.tap_flows_client.delete_tap_flow,
+ tap_flow['id'])
diff --git a/neutron_tempest_plugin/tap_as_a_service/services/__init__.py b/neutron_tempest_plugin/tap_as_a_service/services/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/neutron_tempest_plugin/tap_as_a_service/services/__init__.py
diff --git a/neutron_tempest_plugin/tap_as_a_service/services/taas_client.py b/neutron_tempest_plugin/tap_as_a_service/services/taas_client.py
new file mode 100644
index 0000000..7230cbb
--- /dev/null
+++ b/neutron_tempest_plugin/tap_as_a_service/services/taas_client.py
@@ -0,0 +1,63 @@
+# 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 tempest.lib.services.network import base
+
+
+class TapServicesClient(base.BaseNetworkClient):
+
+ def create_tap_service(self, **kwargs):
+ uri = '/taas/tap_services'
+ post_data = {'tap_service': kwargs}
+ return self.create_resource(uri, post_data)
+
+ def update_tap_service(self, tap_service_id, **kwargs):
+ uri = '/taas/tap_services/%s' % tap_service_id
+ post_data = {'tap_service': kwargs}
+ return self.update_resource(uri, post_data)
+
+ def show_tap_service(self, tap_service_id, **fields):
+ uri = '/taas/tap_services/%s' % tap_service_id
+ return self.show_resource(uri, **fields)
+
+ def delete_tap_service(self, tap_service_id):
+ uri = '/taas/tap_services/%s' % tap_service_id
+ return self.delete_resource(uri)
+
+ def list_tap_services(self, **filters):
+ uri = '/taas/tap_services'
+ return self.list_resources(uri, **filters)
+
+
+class TapFlowsClient(base.BaseNetworkClient):
+
+ def create_tap_flow(self, **kwargs):
+ uri = '/taas/tap_flows'
+ post_data = {'tap_flow': kwargs}
+ return self.create_resource(uri, post_data)
+
+ def update_tap_flow(self, tap_flow_id, **kwargs):
+ uri = '/taas/tap_flows/%s' % tap_flow_id
+ post_data = {'tap_flow': kwargs}
+ return self.update_resource(uri, post_data)
+
+ def show_tap_flow(self, tap_flow_id, **fields):
+ uri = '/taas/tap_flows/%s' % tap_flow_id
+ return self.show_resource(uri, **fields)
+
+ def delete_tap_flow(self, tap_flow_id):
+ uri = '/taas/tap_flows/%s' % tap_flow_id
+ return self.delete_resource(uri)
+
+ def list_tap_flows(self, **filters):
+ uri = '/taas/tap_flows'
+ return self.list_resources(uri, **filters)
diff --git a/zuul.d/master_jobs.yaml b/zuul.d/master_jobs.yaml
index f9fdd05..97be1ce 100644
--- a/zuul.d/master_jobs.yaml
+++ b/zuul.d/master_jobs.yaml
@@ -412,7 +412,7 @@
# TODO(eolivare): Remove OVN_BUILD_FROM_SOURCE once vlan-transparency
# is included in an ovn released version
OVN_BUILD_FROM_SOURCE: True
- OVN_BRANCH: "v20.12.0"
+ OVN_BRANCH: "v21.06.0"
OVS_BRANCH: "branch-2.15"
OVS_SYSCONFDIR: "/usr/local/etc/openvswitch"
devstack_services:
@@ -896,3 +896,93 @@
devstack_localrc:
IPSEC_PACKAGE: strongswan
NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_vpnaas) | join(',') }}"
+
+- job:
+ name: neutron-tempest-plugin-tap-as-a-service
+ parent: neutron-tempest-plugin-base
+ description: |
+ Perform setup common to all tap-as-a-service tempest tests
+ roles:
+ - zuul: openstack/devstack
+ required-projects:
+ - openstack/devstack-gate
+ - openstack/neutron
+ - openstack/neutron-tempest-plugin
+ - openstack/tap-as-a-service
+ - openstack/tempest
+ vars:
+ tempest_test_regex: ^neutron_tempest_plugin\.tap_as_a_service
+ tox_envlist: all
+ network_api_extensions_common: *api_extensions
+ network_api_extensions_tempest:
+ - taas
+ - taas-vlan-filter
+ devstack_localrc:
+ NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_tempest) | join(',') }}"
+ DOWNLOAD_DEFAULT_IMAGES: false
+ IMAGE_URLS: "http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-i386-disk.img,https://cloud-images.ubuntu.com/releases/bionic/release/ubuntu-18.04-server-cloudimg-amd64.img"
+ DEFAULT_IMAGE_NAME: cirros-0.3.4-i386-disk
+ ADVANCED_IMAGE_NAME: ubuntu-18.04-server-cloudimg-amd64
+ BUILD_TIMEOUT: 784
+ Q_AGENT: openvswitch
+ Q_ML2_TENANT_NETWORK_TYPE: vxlan
+ Q_ML2_PLUGIN_MECHANISM_DRIVERS: openvswitch
+ devstack_local_conf:
+ post-config:
+ /$NEUTRON_CORE_PLUGIN_CONF:
+ AGENT:
+ tunnel_types: vxlan,gre
+ test-config:
+ $TEMPEST_CONFIG:
+ taas_plugin_options:
+ advanced_image_ref: ubuntu-18.04-server-cloudimg-amd64
+ advanced_image_ssh_user: ubuntu
+ provider_physical_network: public
+ provider_segmentation_id: 100
+ image_feature_enabled:
+ api_v2: true
+ devstack_plugins:
+ neutron: git://opendev.org/openstack/neutron.git
+ neutron-tempest-plugin: https://opendev.org/openstack/neutron-tempest-plugin.git
+ tap-as-a-service: git://opendev.org/openstack/tap-as-a-service.git
+ devstack_services:
+ # Disable OVN services
+ ovn-controller: false
+ ovn-northd: false
+ ovs-vswitchd: false
+ ovsdb-server: false
+ q-ovn-metadata-agent: false
+ # Enable Neutron services that are not used by OVN
+ q-agt: true
+ q-dhcp: true
+ q-l3: true
+ q-meta: true
+ q-metering: true
+ br-ex-tcpdump: true
+ br-int-flows: true
+ base: false
+ key: true
+ mysql: true
+ rabbit: true
+ g-api: true
+ g-reg: true
+ n-api: true
+ n-cond: true
+ n-cpu: true
+ n-crt: true
+ n-sch: true
+ placement-api: true
+ n-api-meta: true
+ q-svc: true
+ quantum: true
+ taas: true
+ taas_openvswitch_agent: true
+ tempest: true
+ dstat: true
+ irrelevant-files: &tempest-irrelevant-files
+ - ^(test-|)requirements.txt$
+ - ^releasenotes/.*$
+ - ^doc/.*$
+ - ^.*\.rst$
+ - ^tools/.*$
+ - ^tox.ini$
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
index 08fb58c..031860f 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -186,6 +186,7 @@
- neutron-tempest-plugin-vpnaas-ussuri
- neutron-tempest-plugin-vpnaas-victoria
- neutron-tempest-plugin-vpnaas-wallaby
+ - neutron-tempest-plugin-tap-as-a-service
gate:
jobs:
diff --git a/zuul.d/queens_jobs.yaml b/zuul.d/queens_jobs.yaml
index b3e521b..0b56b32 100644
--- a/zuul.d/queens_jobs.yaml
+++ b/zuul.d/queens_jobs.yaml
@@ -245,3 +245,4 @@
USE_PYTHON3: false
CIRROS_VERSION: 0.3.5
TEMPEST_PLUGINS: '"/opt/stack/designate-tempest-plugin /opt/stack/neutron-tempest-plugin"'
+ ADVANCED_INSTANCE_TYPE: ds512M
diff --git a/zuul.d/rocky_jobs.yaml b/zuul.d/rocky_jobs.yaml
index 211e896..5cb6125 100644
--- a/zuul.d/rocky_jobs.yaml
+++ b/zuul.d/rocky_jobs.yaml
@@ -615,6 +615,7 @@
devstack_localrc:
USE_PYTHON3: false
TEMPEST_PLUGINS: '"/opt/stack/designate-tempest-plugin /opt/stack/neutron-tempest-plugin"'
+ ADVANCED_INSTANCE_TYPE: ds512M
branches:
- stable/rocky
diff --git a/zuul.d/stein_jobs.yaml b/zuul.d/stein_jobs.yaml
index 037bba2..f84df2a 100644
--- a/zuul.d/stein_jobs.yaml
+++ b/zuul.d/stein_jobs.yaml
@@ -338,3 +338,5 @@
vars:
branch_override: stable/stein
network_api_extensions_common: *api_extensions
+ devstack_localrc:
+ ADVANCED_INSTANCE_TYPE: ds512M
diff --git a/zuul.d/train_jobs.yaml b/zuul.d/train_jobs.yaml
index a7ac8bf..5caf127 100644
--- a/zuul.d/train_jobs.yaml
+++ b/zuul.d/train_jobs.yaml
@@ -220,6 +220,8 @@
vars:
branch_override: stable/train
network_api_extensions_common: *api_extensions
+ devstack_localrc:
+ ADVANCED_INSTANCE_TYPE: ds512M
- job:
name: neutron-tempest-plugin-sfc-train