diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 77f2db9..0000000 --- a/.gitignore +++ /dev/null @@ -1,58 +0,0 @@ -*.py[cod] - -# C extensions -*.so - -# Packages -*.egg -*.egg-info -dist -build -.eggs -eggs -parts -bin -var -sdist -develop-eggs -.installed.cfg -lib -lib64 - -# Installer logs -pip-log.txt - -# Unit test / coverage reports -.coverage -.tox -nosetests.xml -.testrepository -.stestr -.venv - -# Translations -*.mo - -# Mr Developer -.mr.developer.cfg -.project -.pydevproject - -# Complexity -output/*.html -output/*/index.html - -# Sphinx -doc/build - -# pbr generates these -AUTHORS -ChangeLog - -# Editors -*~ -.*.swp -.*sw? - -# Files created by releasenotes build -releasenotes/build diff --git a/.mailmap b/.mailmap deleted file mode 100644 index 516ae6f..0000000 --- a/.mailmap +++ /dev/null @@ -1,3 +0,0 @@ -# Format is: -# -# diff --git a/.zuul.yaml b/.zuul.yaml deleted file mode 100644 index 2283a92..0000000 --- a/.zuul.yaml +++ /dev/null @@ -1,264 +0,0 @@ -- project: - templates: - - check-requirements - - tempest-plugin-jobs - check: - jobs: - - tap-as-a-service-tempest-plugin: - voting: false - nodeset: openstack-single-node-focal - - tap-as-a-service-tempest-plugin-train: - voting: false - - tap-as-a-service-tempest-plugin-stein: - voting: false - - tap-as-a-service-tempest-plugin-rocky: - voting: false - - tap-as-a-service-tempest-plugin-queens: - voting: false - - tap-as-a-service-tempest-plugin-pike: - voting: false - -- job: - name: tap-as-a-service-tempest-plugin - parent: devstack-tempest - description: | - Perform setup common to all tap-as-a-service tempest tests - roles: - - zuul: openstack/devstack - required-projects: - - openstack/devstack-gate - - openstack/neutron - - openstack/tap-as-a-service - - x/tap-as-a-service-tempest-plugin - - openstack/tempest - vars: - tempest_test_regex: ^neutron_taas_tempest_plugin\. - tempest_concurrency: 4 - tox_envlist: all - network_api_extensions_common: - - agent - - allowed-address-pairs - - auto-allocated-topology - - availability_zone - - binding - - default-subnetpools - - dhcp_agent_scheduler - - dns-domain-ports - - dns-integration - - empty-string-filtering - - ext-gw-mode - - external-net - - extra_dhcp_opt - - extraroute - - filter-validation - - fip-port-details - - flavors - - floatingip-pools - - ip-substring-filtering - - l3-flavors - - l3-ha - - l3_agent_scheduler - - logging - - metering - - multi-provider - - net-mtu - - net-mtu-writable - - network-ip-availability - - network_availability_zone - - pagination - - port-resource-request - - port-mac-address-regenerate - - port-security - - port-security-groups-filtering - - project-id - - provider - - qos - - qos-bw-minimum-ingress - - qos-fip - - quotas - - quota_details - - rbac-policies - - router - - router_availability_zone - - security-group - - segment - - service-type - - sorting - - standard-attr-description - - standard-attr-revisions - - standard-attr-segment - - standard-attr-tag - - standard-attr-timestamp - - subnet_allocation - - trunk - - trunk-details - - uplink-status-propagation - network_api_extensions_tempest: - - taas - - taas-vlan-filter - devstack_localrc: - TEMPEST_PLUGINS: /opt/stack/tap-as-a-service-tempest-plugin - 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 - tap-as-a-service: git://opendev.org/openstack/tap-as-a-service.git - # tempest_plugins: - # - tap-as-a-service-tempest-plugin - devstack_services: - 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 - # Disable OVN services - br-ex-tcpdump: false - br-int-flows: false - ovn-controller: false - ovn-northd: false - ovs-vswitchd: false - ovsdb-server: false - q-ovn-metadata-agent: false - # Neutron services - q-agt: true - q-dhcp: true - q-l3: true - q-meta: true - q-metering: 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$ - -- job: - name: tap-as-a-service-tempest-plugin-base - parent: tap-as-a-service-tempest-plugin - -- job: - name: tap-as-a-service-tempest-plugin-train - parent: tap-as-a-service-tempest-plugin - override-checkout: stable/train - -- job: - name: tap-as-a-service-tempest-plugin-stein - parent: tap-as-a-service-tempest-plugin - override-checkout: stable/stein - -- job: - name: tap-as-a-service-tempest-plugin-rocky - parent: tap-as-a-service-tempest-plugin - override-checkout: stable/rocky - nodeset: openstack-single-node-xenial - vars: - network_api_extensions_tempest: - - taas - devstack_localrc: - USE_PYTHON3: false - tempest_black_regex: | - (?x) # Ignore comments and whitespaces - # bug 1814937 - neutron_taas_tempest_plugin\.tests\.api\.test_taas\.TaaSExtensionTestJSON\.test_delete_tap_resources_after_ts_port_delete - -- job: - name: tap-as-a-service-tempest-plugin-queens - parent: tap-as-a-service-tempest-plugin - override-checkout: stable/queens - nodeset: openstack-single-node-xenial - vars: - network_api_extensions_tempest: - - taas - devstack_localrc: - USE_PYTHON3: false - tempest_black_regex: | - (?x) # Ignore comments and whitespaces - # bug 1814937 - neutron_taas_tempest_plugin\.tests\.api\.test_taas\.TaaSExtensionTestJSON\.test_delete_tap_resources_after_ts_port_delete - -- job: - name: tap-as-a-service-tempest-plugin-pike - parent: tap-as-a-service-tempest-plugin - override-checkout: stable/pike - nodeset: openstack-single-node-xenial - vars: - network_api_extensions_tempest: - - taas - devstack_localrc: - USE_PYTHON3: false - tempest_black_regex: | - (?x) # Ignore comments and whitespaces - # bug 1814937 - neutron_taas_tempest_plugin\.tests\.api\.test_taas\.TaaSExtensionTestJSON\.test_delete_tap_resources_after_ts_port_delete - -- project-template: - name: tap-as-a-service-tempest-plugin-jobs - check: - jobs: - - tap-as-a-service-tempest-plugin - gate: - jobs: - - tap-as-a-service-tempest-plugin - -- project-template: - name: tap-as-a-service-tempest-plugin-jobs-rocky - check: - jobs: - - tap-as-a-service-tempest-plugin-rocky - gate: - jobs: - - tap-as-a-service-tempest-plugin-rocky - -- project-template: - name: tap-as-a-service-tempest-plugin-jobs-queens - check: - jobs: - - tap-as-a-service-tempest-plugin-queens - gate: - jobs: - - tap-as-a-service-tempest-plugin-queens - -- project-template: - name: tap-as-a-service-tempest-plugin-jobs-pike - check: - jobs: - - tap-as-a-service-tempest-plugin-pike - gate: - jobs: - - tap-as-a-service-tempest-plugin-pike diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index 0d1cd33..0000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,17 +0,0 @@ -If you would like to contribute to the development of OpenStack, you must -follow the steps in this page: - - https://docs.openstack.org/infra/manual/developers.html - -If you already have a good understanding of how the system works and your -OpenStack accounts are set up, you can skip to the development workflow -section of this documentation to learn how changes to OpenStack should be -submitted for review via the Gerrit tool: - - https://docs.openstack.org/infra/manual/developers.html#development-workflow - -Pull requests submitted through GitHub will be ignored. - -Bugs should be filed on Launchpad, not GitHub: - - https://bugs.launchpad.net/tap-as-a-service diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 68c771a..0000000 --- a/LICENSE +++ /dev/null @@ -1,176 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - diff --git a/README.rst b/README.rst index b621a34..2ada541 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,15 @@ -=================================== -Tempest plugin for Tap as a Service -=================================== +This project is no longer maintained. + +The contents of this repository are still available in the Git +source code management system. To see the contents of this +repository before it reached its end of life, please check out the +previous commit with "git checkout HEAD^1". + +The content of tap-as-a-service-tempest-plugin was moved to +neutron-tempest-plugin and maintained there: +https://opendev.org/openstack/neutron-tempest-plugin/src/branch/master/neutron_tempest_plugin/tap_as_a_service + +For any further questions, please email +openstack-discuss@lists.openstack.org or join #openstack-dev on +OFTC. -This repository contains tempest plugin for tap-as-a-service. diff --git a/neutron_taas_tempest_plugin/__init__.py b/neutron_taas_tempest_plugin/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/neutron_taas_tempest_plugin/config.py b/neutron_taas_tempest_plugin/config.py deleted file mode 100644 index df43595..0000000 --- a/neutron_taas_tempest_plugin/config.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright (c) 2018 AT&T Corporation -# 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. - -from oslo_config import cfg -from tempest import config - - -CONF = config.CONF - - -taas_plugin_group = cfg.OptGroup(name='taas_plugin_options', - title='TaaS Tempest Plugin Options') - -TaaSPluginGroup = [ - cfg.StrOpt('provider_physical_network', - default='', - help='Physical network to be used for creating SRIOV network.'), - cfg.StrOpt('provider_segmentation_id', - default='', - help='Segmentation-id to be used for creating SRIOV network.'), - cfg.StrOpt('vlan_filter', - default='', - help='Comma separated list of VLANs to be mirrored ' - 'for a Tap-Flow.'), - cfg.StrOpt('advanced_image_ref', - default='', - help='Valid advanced image uuid to be used in tests. ' - 'Must contain tcpdump preinstalled.'), - cfg.StrOpt('advanced_image_ssh_user', - default='ubuntu', - help='Name of ssh user to use with advanced image in tests.'), - cfg.StrOpt('advanced_image_flavor_ref', - default='d1', - help='Valid flavor to use with advanced image in tests.'), -] diff --git a/neutron_taas_tempest_plugin/plugin.py b/neutron_taas_tempest_plugin/plugin.py deleted file mode 100644 index 4bd41f2..0000000 --- a/neutron_taas_tempest_plugin/plugin.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright (c) 2015 Midokura SARL -# 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 os - -from tempest.test_discover import plugins - -from neutron_taas_tempest_plugin import config as project_config - - -class NeutronTaaSPlugin(plugins.TempestPlugin): - def get_opt_lists(self): - return [(project_config.taas_plugin_group.name, - project_config.TaaSPluginGroup)] - - def load_tests(self): - this_dir = os.path.dirname(os.path.abspath(__file__)) - # top_level_dir = $(this_dir)/.. - top_level_dir = os.path.split(this_dir)[0] - test_dir = os.path.join(top_level_dir, - 'neutron_taas_tempest_plugin/tests') - return (test_dir, top_level_dir) - - def register_opts(self, conf): - conf.register_group(project_config.taas_plugin_group) - conf.register_opts(project_config.TaaSPluginGroup, - project_config.taas_plugin_group) diff --git a/neutron_taas_tempest_plugin/services/__init__.py b/neutron_taas_tempest_plugin/services/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/neutron_taas_tempest_plugin/services/client.py b/neutron_taas_tempest_plugin/services/client.py deleted file mode 100644 index 73c8e86..0000000 --- a/neutron_taas_tempest_plugin/services/client.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright (c) 2015 Midokura SARL -# 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. - -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/neutron_taas_tempest_plugin/tests/__init__.py b/neutron_taas_tempest_plugin/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/neutron_taas_tempest_plugin/tests/api/__init__.py b/neutron_taas_tempest_plugin/tests/api/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/neutron_taas_tempest_plugin/tests/api/base.py b/neutron_taas_tempest_plugin/tests/api/base.py deleted file mode 100644 index c3f57e4..0000000 --- a/neutron_taas_tempest_plugin/tests/api/base.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (c) 2015 Midokura SARL -# 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. - -from tempest.api.network import base - -from neutron_taas_tempest_plugin.tests import taas_client - - -class BaseTaaSTest(taas_client.TaaSClientMixin, base.BaseNetworkTest): - pass diff --git a/neutron_taas_tempest_plugin/tests/api/test_taas.py b/neutron_taas_tempest_plugin/tests/api/test_taas.py deleted file mode 100644 index 6437076..0000000 --- a/neutron_taas_tempest_plugin/tests/api/test_taas.py +++ /dev/null @@ -1,133 +0,0 @@ -# Copyright (c) 2018 AT&T Intellectual Property. All other rights reserved. -# Copyright (c) 2015 Midokura SARL -# 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. - -from tempest.common import utils -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -from neutron_taas_tempest_plugin.tests.api 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_taas_tempest_plugin/tests/scenario/__init__.py b/neutron_taas_tempest_plugin/tests/scenario/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/neutron_taas_tempest_plugin/tests/scenario/base.py b/neutron_taas_tempest_plugin/tests/scenario/base.py deleted file mode 100644 index 626f9f9..0000000 --- a/neutron_taas_tempest_plugin/tests/scenario/base.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (c) 2015 Midokura SARL -# 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. - -from neutron_taas_tempest_plugin.tests.scenario import manager -from neutron_taas_tempest_plugin.tests import taas_client - - -class TaaSScenarioTest(taas_client.TaaSClientMixin, - manager.NetworkScenarioTest): - pass diff --git a/neutron_taas_tempest_plugin/tests/scenario/manager.py b/neutron_taas_tempest_plugin/tests/scenario/manager.py deleted file mode 100644 index 02b481c..0000000 --- a/neutron_taas_tempest_plugin/tests/scenario/manager.py +++ /dev/null @@ -1,1000 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# Copyright 2013 IBM Corp. -# 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 subprocess - -import netaddr -from oslo_log import log -from oslo_utils import netutils - -from tempest.common import compute -from tempest.common.utils.linux import remote_client -from tempest.common.utils import net_utils -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import exceptions as lib_exc -import tempest.test - -CONF = config.CONF - -LOG = log.getLogger(__name__) - - -class ScenarioTest(tempest.test.BaseTestCase): - """Base class for scenario tests. Uses tempest own clients. """ - - credentials = ['primary', 'admin'] - - @classmethod - def setup_clients(cls): - super(ScenarioTest, cls).setup_clients() - # Clients (in alphabetical order) - cls.keypairs_client = cls.os_primary.keypairs_client - cls.servers_client = cls.os_primary.servers_client - # Neutron network client - cls.networks_client = cls.os_primary.networks_client - cls.ports_client = cls.os_primary.ports_client - cls.routers_client = cls.os_primary.routers_client - cls.subnets_client = cls.os_primary.subnets_client - cls.flavor_client = cls.os_primary.flavors_client - cls.floating_ips_client = cls.os_primary.floating_ips_client - cls.security_groups_client = cls.os_primary.security_groups_client - cls.security_group_rules_client = ( - cls.os_primary.security_group_rules_client) - cls.admin_networks_client = cls.os_admin.networks_client - cls.admin_subnets_client = cls.os_admin.subnets_client - cls.admin_routers_client = cls.os_admin.routers_client - - # ## Test functions library - # - # The create_[resource] functions only return body and discard the - # resp part which is not used in scenario tests - - def _create_port(self, network_id, client=None, namestart='port-quotatest', - **kwargs): - if not client: - client = self.ports_client - name = data_utils.rand_name(namestart) - result = client.create_port( - name=name, - network_id=network_id, - **kwargs) - self.assertIsNotNone(result, 'Unable to allocate port') - port = result['port'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - client.delete_port, port['id']) - return port - - @classmethod - def create_keypair(cls, client=None): - if not client: - client = cls.keypairs_client - name = data_utils.rand_name(cls.__class__.__name__) - # We don't need to create a keypair by pubkey in scenario - body = client.create_keypair(name=name) - cls.addClassResourceCleanup(client.delete_keypair, name) - return body['keypair'] - - def create_server(self, name=None, image_id=None, flavor=None, - validatable=False, wait_until='ACTIVE', - clients=None, **kwargs): - """Wrapper utility that returns a test server. - - This wrapper utility calls the common create test server and - returns a test server. The purpose of this wrapper is to minimize - the impact on the code of the tests already using this - function. - """ - - # NOTE(jlanoux): As a first step, ssh checks in the scenario - # tests need to be run regardless of the run_validation and - # validatable parameters and thus until the ssh validation job - # becomes voting in CI. The test resources management and IP - # association are taken care of in the scenario tests. - # Therefore, the validatable parameter is set to false in all - # those tests. In this way create_server just return a standard - # server and the scenario tests always perform ssh checks. - - # Needed for the cross_tenant_traffic test: - if clients is None: - clients = self.os_primary - - if name is None: - name = data_utils.rand_name(self.__class__.__name__ + "-server") - - vnic_type = CONF.network.port_vnic_type - - # If vnic_type is configured create port for - # every network - if vnic_type: - ports = [] - - create_port_body = {'binding:vnic_type': vnic_type, - 'namestart': 'port-smoke'} - if kwargs: - # Convert security group names to security group ids - # to pass to create_port - if 'security_groups' in kwargs: - security_groups = \ - clients.security_groups_client.list_security_groups( - ).get('security_groups') - sec_dict = dict([(s['name'], s['id']) - for s in security_groups]) - - sec_groups_names = [s['name'] for s in kwargs.pop( - 'security_groups')] - security_groups_ids = [sec_dict[s] - for s in sec_groups_names] - - if security_groups_ids: - create_port_body[ - 'security_groups'] = security_groups_ids - networks = kwargs.pop('networks', []) - else: - networks = [] - - # If there are no networks passed to us we look up - # for the project's private networks and create a port. - # The same behaviour as we would expect when passing - # the call to the clients with no networks - if not networks: - networks = clients.networks_client.list_networks( - **{'router:external': False, 'fields': 'id'})['networks'] - - # It's net['uuid'] if networks come from kwargs - # and net['id'] if they come from - # clients.networks_client.list_networks - for net in networks: - net_id = net.get('uuid', net.get('id')) - if 'port' not in net: - port = self._create_port(network_id=net_id, - client=clients.ports_client, - **create_port_body) - ports.append({'port': port['id']}) - else: - ports.append({'port': net['port']}) - if ports: - kwargs['networks'] = ports - self.ports = ports - - tenant_network = self.get_tenant_network() - - body, servers = compute.create_test_server( - clients, - tenant_network=tenant_network, - wait_until=wait_until, - name=name, flavor=flavor, - image_id=image_id, **kwargs) - - self.addCleanup(waiters.wait_for_server_termination, - clients.servers_client, body['id']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - clients.servers_client.delete_server, body['id']) - server = clients.servers_client.show_server(body['id'])['server'] - return server - - def get_remote_client(self, ip_address, username=None, private_key=None): - """Get a SSH client to a remote server - - @param ip_address the server floating or fixed IP address to use - for ssh validation - @param username name of the Linux account on the remote server - @param private_key the SSH private key to use - @return a RemoteClient object - """ - - if username is None: - username = CONF.validation.image_ssh_user - # Set this with 'keypair' or others to log in with keypair or - # username/password. - if CONF.validation.auth_method == 'keypair': - password = None - if private_key is None: - private_key = self.keypair['private_key'] - else: - password = CONF.validation.image_ssh_password - private_key = None - linux_client = remote_client.RemoteClient(ip_address, username, - pkey=private_key, - password=password) - try: - linux_client.validate_authentication() - except Exception as e: - message = ('Initializing SSH connection to %(ip)s failed. ' - 'Error: %(error)s' % {'ip': ip_address, - 'error': e}) - caller = test_utils.find_test_caller() - if caller: - message = '(%s) %s' % (caller, message) - LOG.exception(message) - self._log_console_output() - raise - - return linux_client - - def _log_console_output(self, servers=None): - if not CONF.compute_feature_enabled.console_output: - LOG.debug('Console output not supported, cannot log') - return - if not servers: - servers = self.servers_client.list_servers() - servers = servers['servers'] - for server in servers: - try: - console_output = self.servers_client.get_console_output( - server['id'])['output'] - LOG.debug('Console output for %s\nbody=\n%s', - server['id'], console_output) - except lib_exc.NotFound: - LOG.debug("Server %s disappeared(deleted) while looking " - "for the console log", server['id']) - - def _log_net_info(self, exc): - # network debug is called as part of ssh init - if not isinstance(exc, lib_exc.SSHTimeout): - LOG.debug('Network information on a devstack host') - - def ping_ip_address(self, ip_address, should_succeed=True, - ping_timeout=None, mtu=None): - timeout = ping_timeout or CONF.validation.ping_timeout - cmd = ['ping', '-c1', '-w1'] - - if mtu: - cmd += [ - # don't fragment - '-M', 'do', - # ping receives just the size of ICMP payload - '-s', str(net_utils.get_ping_payload_size(mtu, 4)) - ] - cmd.append(ip_address) - - def ping(): - proc = subprocess.Popen(cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - proc.communicate() - - return (proc.returncode == 0) == should_succeed - - caller = test_utils.find_test_caller() - LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the' - ' expected result is %(should_succeed)s', { - 'caller': caller, 'ip': ip_address, 'timeout': timeout, - 'should_succeed': - 'reachable' if should_succeed else 'unreachable' - }) - result = test_utils.call_until_true(ping, timeout, 1) - LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the ' - 'ping result is %(result)s', { - 'caller': caller, 'ip': ip_address, 'timeout': timeout, - 'result': 'expected' if result else 'unexpected' - }) - return result - - def check_vm_connectivity(self, ip_address, - username=None, - private_key=None, - should_connect=True, - mtu=None): - """Check server connectivity - - :param ip_address: server to test against - :param username: server's ssh username - :param private_key: server's ssh private key to be used - :param should_connect: True/False indicates positive/negative test - positive - attempt ping and ssh - negative - attempt ping and fail if succeed - :param mtu: network MTU to use for connectivity validation - - :raises: AssertError if the result of the connectivity check does - not match the value of the should_connect param - """ - if should_connect: - msg = "Timed out waiting for %s to become reachable" % ip_address - else: - msg = "ip address %s is reachable" % ip_address - self.assertTrue(self.ping_ip_address(ip_address, - should_succeed=should_connect, - mtu=mtu), - msg=msg) - if should_connect: - # no need to check ssh for negative connectivity - self.get_remote_client(ip_address, username, private_key) - - def check_public_network_connectivity(self, ip_address, username, - private_key, should_connect=True, - msg=None, servers=None, mtu=None): - # The target login is assumed to have been configured for - # key-based authentication by cloud-init. - LOG.debug('checking network connections to IP %s with user: %s', - ip_address, username) - try: - self.check_vm_connectivity(ip_address, - username, - private_key, - should_connect=should_connect, - mtu=mtu) - except Exception: - ex_msg = 'Public network connectivity check failed' - if msg: - ex_msg += ": " + msg - LOG.exception(ex_msg) - self._log_console_output(servers) - raise - - -class NetworkScenarioTest(ScenarioTest): - """Base class for network scenario tests. - - This class provide helpers for network scenario tests, using the neutron - API. Helpers from ancestor which use the nova network API are overridden - with the neutron API. - - This Class also enforces using Neutron instead of novanetwork. - Subclassed tests will be skipped if Neutron is not enabled - - """ - - credentials = ['primary', 'admin'] - - @classmethod - def skip_checks(cls): - super(NetworkScenarioTest, cls).skip_checks() - if not CONF.service_available.neutron: - raise cls.skipException('Neutron not available') - - @classmethod - def _create_network(cls, networks_client=None, - tenant_id=None, - namestart='network-smoke-', - port_security_enabled=True): - if not networks_client: - networks_client = cls.networks_client - if not tenant_id: - tenant_id = networks_client.tenant_id - name = data_utils.rand_name(namestart) - network_kwargs = dict(name=name, tenant_id=tenant_id) - # Neutron disables port security by default so we have to check the - # config before trying to create the network with port_security_enabled - if CONF.network_feature_enabled.port_security: - network_kwargs['port_security_enabled'] = port_security_enabled - result = networks_client.create_network(**network_kwargs) - network = result['network'] - - assert network['name'] == name - cls.addClassResourceCleanup(test_utils.call_and_ignore_notfound_exc, - networks_client.delete_network, - network['id']) - return network - - @classmethod - def _create_subnet(cls, network, subnets_client=None, - routers_client=None, namestart='subnet-smoke', - **kwargs): - """Create a subnet for the given network - - within the cidr block configured for tenant networks. - """ - if not subnets_client: - subnets_client = cls.subnets_client - if not routers_client: - routers_client = cls.routers_client - - def cidr_in_use(cidr, tenant_id): - """Check cidr existence - - :returns: True if subnet with cidr already exist in tenant - False else - """ - cidr_in_use = cls.os_admin.subnets_client.list_subnets( - tenant_id=tenant_id, cidr=cidr)['subnets'] - return len(cidr_in_use) != 0 - - ip_version = kwargs.pop('ip_version', 4) - - if ip_version == 6: - tenant_cidr = netaddr.IPNetwork( - CONF.network.project_network_v6_cidr) - num_bits = CONF.network.project_network_v6_mask_bits - else: - tenant_cidr = netaddr.IPNetwork(CONF.network.project_network_cidr) - num_bits = CONF.network.project_network_mask_bits - - result = None - str_cidr = None - # Repeatedly attempt subnet creation with sequential cidr - # blocks until an unallocated block is found. - for subnet_cidr in tenant_cidr.subnet(num_bits): - str_cidr = str(subnet_cidr) - if cidr_in_use(str_cidr, tenant_id=network['tenant_id']): - continue - - subnet = dict( - name=data_utils.rand_name(namestart), - network_id=network['id'], - tenant_id=network['tenant_id'], - cidr=str_cidr, - ip_version=ip_version, - **kwargs - ) - try: - result = subnets_client.create_subnet(**subnet) - break - except lib_exc.Conflict as e: - is_overlapping_cidr = 'overlaps with another subnet' in str(e) - if not is_overlapping_cidr: - raise - assert result is not None, 'Unable to allocate tenant network' - - subnet = result['subnet'] - assert subnet['cidr'] == str_cidr - - cls.addClassResourceCleanup( - test_utils.call_and_ignore_notfound_exc, - subnets_client.delete_subnet, subnet['id']) - - return subnet - - def _get_server_port_id_and_ip4(self, server, ip_addr=None): - ports = self.os_admin.ports_client.list_ports( - device_id=server['id'], fixed_ip=ip_addr)['ports'] - # A port can have more than one IP address in some cases. - # If the network is dual-stack (IPv4 + IPv6), this port is associated - # with 2 subnets - p_status = ['ACTIVE'] - # NOTE(vsaienko) With Ironic, instances live on separate hardware - # servers. Neutron does not bind ports for Ironic instances, as a - # result the port remains in the DOWN state. - # TODO(vsaienko) remove once bug: #1599836 is resolved. - if getattr(CONF.service_available, 'ironic', False): - p_status.append('DOWN') - port_map = [(p["id"], fxip["ip_address"]) - for p in ports - for fxip in p["fixed_ips"] - if netutils.is_valid_ipv4(fxip["ip_address"]) and - p['status'] in p_status] - inactive = [p for p in ports if p['status'] != 'ACTIVE'] - if inactive: - LOG.warning("Instance has ports that are not ACTIVE: %s", inactive) - - self.assertNotEqual(0, len(port_map), - "No IPv4 addresses found in: %s" % ports) - self.assertEqual(len(port_map), 1, - "Found multiple IPv4 addresses: %s. " - "Unable to determine which port to target." - % port_map) - return port_map[0] - - def _get_network_by_name(self, network_name): - net = self.os_admin.networks_client.list_networks( - name=network_name)['networks'] - self.assertNotEqual(len(net), 0, - "Unable to get network by name: %s" % network_name) - return net[0] - - def create_floating_ip(self, thing, external_network_id=None, - port_id=None, client=None): - """Create a floating IP and associates to a resource/port on Neutron""" - if not external_network_id: - external_network_id = CONF.network.public_network_id - if not client: - client = self.floating_ips_client - if not port_id: - port_id, ip4 = self._get_server_port_id_and_ip4(thing) - else: - ip4 = None - result = client.create_floatingip( - floating_network_id=external_network_id, - port_id=port_id, - tenant_id=thing['tenant_id'], - fixed_ip_address=ip4 - ) - floating_ip = result['floatingip'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - client.delete_floatingip, - floating_ip['id']) - return floating_ip - - def _associate_floating_ip(self, floating_ip, server): - port_id, _ = self._get_server_port_id_and_ip4(server) - kwargs = dict(port_id=port_id) - floating_ip = self.floating_ips_client.update_floatingip( - floating_ip['id'], **kwargs)['floatingip'] - self.assertEqual(port_id, floating_ip['port_id']) - return floating_ip - - def _disassociate_floating_ip(self, floating_ip): - """:param floating_ip: floating_ips_client.create_floatingip""" - kwargs = dict(port_id=None) - floating_ip = self.floating_ips_client.update_floatingip( - floating_ip['id'], **kwargs)['floatingip'] - self.assertIsNone(floating_ip['port_id']) - return floating_ip - - def check_floating_ip_status(self, floating_ip, status): - """Verifies floatingip reaches the given status - - :param dict floating_ip: floating IP dict to check status - :param status: target status - :raises: AssertionError if status doesn't match - """ - floatingip_id = floating_ip['id'] - - def refresh(): - result = (self.floating_ips_client. - show_floatingip(floatingip_id)['floatingip']) - return status == result['status'] - - test_utils.call_until_true(refresh, - CONF.network.build_timeout, - CONF.network.build_interval) - floating_ip = self.floating_ips_client.show_floatingip( - floatingip_id)['floatingip'] - self.assertEqual(status, floating_ip['status'], - message="FloatingIP: {fp} is at status: {cst}. " - "failed to reach status: {st}" - .format(fp=floating_ip, cst=floating_ip['status'], - st=status)) - LOG.info("FloatingIP: {fp} is at status: {st}" - .format(fp=floating_ip, st=status)) - - def _check_tenant_network_connectivity(self, server, - username, - private_key, - should_connect=True, - servers_for_debug=None): - if not CONF.network.project_networks_reachable: - msg = 'Tenant networks not configured to be reachable.' - LOG.info(msg) - return - # The target login is assumed to have been configured for - # key-based authentication by cloud-init. - try: - for net_name, ip_addresses in server['addresses'].items(): - for ip_address in ip_addresses: - self.check_vm_connectivity(ip_address['addr'], - username, - private_key, - should_connect=should_connect) - except Exception as e: - LOG.exception('Tenant network connectivity check failed') - self._log_console_output(servers_for_debug) - self._log_net_info(e) - raise - - def _check_remote_connectivity(self, source, dest, should_succeed=True, - nic=None): - """check ping server via source ssh connection - - :param source: RemoteClient: an ssh connection from which to ping - :param dest: and IP to ping against - :param should_succeed: boolean should ping succeed or not - :param nic: specific network interface to ping from - :returns: boolean -- should_succeed == ping - :returns: ping is false if ping failed - """ - def ping_remote(): - try: - source.ping_host(dest, nic=nic) - except lib_exc.SSHExecCommandFailed: - LOG.warning('Failed to ping IP: %s via a ssh connection ' - 'from: %s.', dest, source.ssh_client.host) - return not should_succeed - return should_succeed - - return test_utils.call_until_true(ping_remote, - CONF.validation.ping_timeout, - 1) - - @classmethod - def _create_security_group(cls, security_group_rules_client=None, - tenant_id=None, - namestart='secgroup-smoke', - security_groups_client=None): - if security_group_rules_client is None: - security_group_rules_client = cls.security_group_rules_client - if security_groups_client is None: - security_groups_client = cls.security_groups_client - if tenant_id is None: - tenant_id = security_groups_client.tenant_id - secgroup = cls._create_empty_security_group( - namestart=namestart, client=security_groups_client, - tenant_id=tenant_id) - - # Add rules to the security group - rules = cls._create_loginable_secgroup_rule( - security_group_rules_client=security_group_rules_client, - secgroup=secgroup, - security_groups_client=security_groups_client) - for rule in rules: - assert tenant_id == rule['tenant_id'] - assert secgroup['id'] == rule['security_group_id'] - return secgroup - - @classmethod - def _create_empty_security_group(cls, client=None, tenant_id=None, - namestart='secgroup-smoke'): - """Create a security group without rules. - - Default rules will be created: - - IPv4 egress to any - - IPv6 egress to any - - :param tenant_id: secgroup will be created in this tenant - :returns: the created security group - """ - if client is None: - client = cls.security_groups_client - if not tenant_id: - tenant_id = client.tenant_id - sg_name = data_utils.rand_name(namestart) - sg_desc = sg_name + " description" - sg_dict = dict(name=sg_name, - description=sg_desc) - sg_dict['tenant_id'] = tenant_id - result = client.create_security_group(**sg_dict) - - secgroup = result['security_group'] - assert secgroup['name'] == sg_name - assert tenant_id == secgroup['tenant_id'] - assert secgroup['description'] == sg_desc - - cls.addClassResourceCleanup( - test_utils.call_and_ignore_notfound_exc, - client.delete_security_group, secgroup['id']) - return secgroup - - @classmethod - def _default_security_group(cls, client=None, tenant_id=None): - """Get default secgroup for given tenant_id. - - :returns: default secgroup for given tenant - """ - if client is None: - client = cls.security_groups_client - if not tenant_id: - tenant_id = client.tenant_id - sgs = [ - sg for sg in list(client.list_security_groups().values())[0] - if sg['tenant_id'] == tenant_id and sg['name'] == 'default' - ] - msg = "No default security group for tenant %s." % (tenant_id) - assert len(sgs) > 0, msg - return sgs[0] - - @classmethod - def _create_security_group_rule(cls, secgroup=None, - sec_group_rules_client=None, - tenant_id=None, - security_groups_client=None, **kwargs): - """Create a rule from a dictionary of rule parameters. - - Create a rule in a secgroup. if secgroup not defined will search for - default secgroup in tenant_id. - - :param secgroup: the security group. - :param tenant_id: if secgroup not passed -- the tenant in which to - search for default secgroup - :param kwargs: a dictionary containing rule parameters: - for example, to allow incoming ssh: - rule = { - direction: 'ingress' - protocol:'tcp', - port_range_min: 22, - port_range_max: 22 - } - """ - if sec_group_rules_client is None: - sec_group_rules_client = cls.security_group_rules_client - if security_groups_client is None: - security_groups_client = cls.security_groups_client - if not tenant_id: - tenant_id = security_groups_client.tenant_id - if secgroup is None: - secgroup = cls._default_security_group( - client=security_groups_client, tenant_id=tenant_id) - - ruleset = dict(security_group_id=secgroup['id'], - tenant_id=secgroup['tenant_id']) - ruleset.update(kwargs) - - sg_rule = sec_group_rules_client.create_security_group_rule(**ruleset) - sg_rule = sg_rule['security_group_rule'] - - assert secgroup['tenant_id'] == sg_rule['tenant_id'] - assert secgroup['id'] == sg_rule['security_group_id'] - - return sg_rule - - @classmethod - def _create_loginable_secgroup_rule(cls, security_group_rules_client=None, - secgroup=None, - security_groups_client=None): - """Create loginable security group rule - - This function will create: - 1. egress and ingress tcp port 22 allow rule in order to allow ssh - access for ipv4. - 2. egress and ingress ipv6 icmp allow rule, in order to allow icmpv6. - 3. egress and ingress ipv4 icmp allow rule, in order to allow icmpv4. - """ - - if security_group_rules_client is None: - security_group_rules_client = cls.security_group_rules_client - if security_groups_client is None: - security_groups_client = cls.security_groups_client - rules = [] - rulesets = [ - dict( - # ssh - protocol='tcp', - port_range_min=22, - port_range_max=22, - ), - dict( - # ping - protocol='icmp', - ), - dict( - # ipv6-icmp for ping6 - protocol='icmp', - ethertype='IPv6', - ) - ] - sec_group_rules_client = security_group_rules_client - for ruleset in rulesets: - for r_direction in ['ingress', 'egress']: - ruleset['direction'] = r_direction - try: - sg_rule = cls._create_security_group_rule( - sec_group_rules_client=sec_group_rules_client, - secgroup=secgroup, - security_groups_client=security_groups_client, - **ruleset) - except lib_exc.Conflict as ex: - # if rule already exist - skip rule and continue - msg = 'Security group rule already exists' - if msg not in ex._error_string: - raise ex - else: - assert r_direction == sg_rule['direction'] - rules.append(sg_rule) - - return rules - - @classmethod - def _get_router(cls, client=None, tenant_id=None): - """Retrieve a router for the given tenant id. - - If a public router has been configured, it will be returned. - - If a public router has not been configured, but a public - network has, a tenant router will be created and returned that - routes traffic to the public network. - """ - if not client: - client = cls.routers_client - if not tenant_id: - tenant_id = client.tenant_id - router_id = CONF.network.public_router_id - network_id = CONF.network.public_network_id - if router_id: - body = client.show_router(router_id) - return body['router'] - elif network_id: - router = cls._create_router(client, tenant_id) - kwargs = {'external_gateway_info': dict(network_id=network_id)} - router = client.update_router(router['id'], **kwargs)['router'] - return router - else: - raise Exception("Neither of 'public_router_id' or " - "'public_network_id' has been defined.") - - @classmethod - def _create_router(cls, client=None, tenant_id=None, - namestart='router-smoke'): - if not client: - client = cls.routers_client - if not tenant_id: - tenant_id = client.tenant_id - name = data_utils.rand_name(namestart) - result = client.create_router(name=name, - admin_state_up=True, - tenant_id=tenant_id) - router = result['router'] - assert router['name'] == name - cls.addClassResourceCleanup(test_utils.call_and_ignore_notfound_exc, - client.delete_router, - router['id']) - return router - - def _update_router_admin_state(self, router, admin_state_up): - kwargs = dict(admin_state_up=admin_state_up) - router = self.routers_client.update_router( - router['id'], **kwargs)['router'] - self.assertEqual(admin_state_up, router['admin_state_up']) - - @classmethod - def create_networks(cls, networks_client=None, - routers_client=None, subnets_client=None, - tenant_id=None, dns_nameservers=None, - port_security_enabled=True): - """Create a network with a subnet connected to a router. - - The baremetal driver is a special case since all nodes are - on the same shared network. - - :param tenant_id: id of tenant to create resources in. - :param dns_nameservers: list of dns servers to send to subnet. - :returns: network, subnet, router - """ - if CONF.network.shared_physical_network: - # NOTE(Shrews): This exception is for environments where tenant - # credential isolation is available, but network separation is - # not (the current baremetal case). Likely can be removed when - # test account mgmt is reworked: - # https://blueprints.launchpad.net/tempest/+spec/test-accounts - if not CONF.compute.fixed_network_name: - m = 'fixed_network_name must be specified in config' - raise lib_exc.InvalidConfiguration(m) - network = cls._get_network_by_name( - CONF.compute.fixed_network_name) - router = None - subnet = None - else: - network = cls._create_network( - networks_client=networks_client, - tenant_id=tenant_id, - port_security_enabled=port_security_enabled) - router = cls._get_router(client=routers_client, - tenant_id=tenant_id) - subnet_kwargs = dict(network=network, - subnets_client=subnets_client, - routers_client=routers_client) - # use explicit check because empty list is a valid option - if dns_nameservers is not None: - subnet_kwargs['dns_nameservers'] = dns_nameservers - subnet = cls._create_subnet(**subnet_kwargs) - if not routers_client: - routers_client = cls.routers_client - router_id = router['id'] - routers_client.add_router_interface(router_id, - subnet_id=subnet['id']) - - # save a cleanup job to remove this association between - # router and subnet - cls.addClassResourceCleanup( - test_utils.call_and_ignore_notfound_exc, - routers_client.remove_router_interface, router_id, - subnet_id=subnet['id']) - return network, subnet, router - - def _create_server_and_wait(self, source_port, image_id=None, - flavor_id=None): - image_id = image_id if image_id else CONF.compute.image_ref - flavor_id = flavor_id if flavor_id else CONF.compute.flavor_ref - - vm = self.create_server( - flavor=flavor_id, - image_id=image_id, - key_name=self.keypair['name'], - wait_until='ACTIVE', - networks=[{'port': source_port['id']}]) - - return vm - - def _create_server_with_floatingip(self, use_taas_cloud_image=False, - provider_net=False, **kwargs): - net_id = self.network['id'] - flavor = CONF.compute.flavor_ref - image = CONF.compute.image_ref - if use_taas_cloud_image: - image = self._get_real_image_id( - CONF.taas_plugin_options.advanced_image_ref) - flavor = self._get_real_flavor_id( - CONF.taas_plugin_options.advanced_image_flavor_ref) - - if provider_net: - net_id = self.provider_network['id'] - - port = self._create_port( - net_id, security_groups=[self.secgroup['id']], **kwargs) - self._create_server_and_wait(port, image, flavor) - - fip = self.create_floating_ip( - port, port_id=port['id'], - external_network_id=CONF.network.public_network_id) - - return port, fip - - def _run_in_background(self, sshclient, cmd): - runInBg = "nohup %s 2>&1 &" % cmd - sshclient.exec_command(runInBg) - - def _setup_provider_network(self): - net = self._create_provider_network() - self._create_provider_subnet(net["id"]) - return net - - def _create_provider_network(self): - network_kwargs = { - "admin_state_up": True, - "shared": True, - "provider:network_type": "vlan", - "provider:physical_network": - CONF.taas_plugin_options.provider_physical_network, - } - - segmentation_id = CONF.taas_plugin_options.provider_segmentation_id - if segmentation_id and segmentation_id == "0": - network_kwargs['provider:network_type'] = 'flat' - elif segmentation_id: - network_kwargs['provider:segmentation_id'] = segmentation_id - - network = self.admin_networks_client.create_network( - **network_kwargs)['network'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.admin_networks_client.delete_network, - network['id']) - - return network - - def _create_provider_subnet(self, net_id): - subnet = dict( - network_id=net_id, - cidr="172.25.100.0/24", - ip_version=4, - ) - result = self.admin_subnets_client.create_subnet(**subnet) - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.admin_subnets_client.delete_subnet, result['subnet']['id']) - - self.admin_routers_client.add_router_interface( - self.router['id'], subnet_id=result['subnet']['id']) - - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.admin_routers_client.remove_router_interface, - self.router['id'], subnet_id=result['subnet']['id']) - - def _get_real_image_id(self, image_id): - try: - id = self.image_client.show_image( - image_id=image_id)["id"] - except AssertionError: - images = self.image_client.list_images( - params={"name": image_id})["images"] - if len(images) == 0: - self.skip_checks() - id = images[0]["id"] - return id - - def _get_real_flavor_id(self, flavor_id): - id = None - try: - id = self.flavor_client.show_flavor( - flavor_id=flavor_id)["flavor"]["id"] - except AssertionError: - flavors = self.flavor_client.list_flavors()["flavors"] - for f in flavors: - if f["name"] == flavor_id: - id = f["id"] - if id is None: - self.skip_checks() - return id diff --git a/neutron_taas_tempest_plugin/tests/scenario/test_taas.py b/neutron_taas_tempest_plugin/tests/scenario/test_taas.py deleted file mode 100644 index 1c8d53a..0000000 --- a/neutron_taas_tempest_plugin/tests/scenario/test_taas.py +++ /dev/null @@ -1,277 +0,0 @@ -# Copyright (c) 2015 Midokura SARL -# 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. - -from oslo_log import log as logging -from tempest.common import utils -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -import testtools - -from neutron_taas_tempest_plugin.tests.scenario import base - -CONF = config.CONF -LOG = logging.getLogger(__name__) - - -# pylint: disable=too-many-ancestors -class TestTaaS(base.TaaSScenarioTest): - """Config Requirement in tempest.conf: - - - project_network_cidr_bits- specifies the subnet range for each network - - project_network_cidr - - public_network_id. - """ - - @classmethod - @utils.requires_ext(extension='taas', service='network') - @utils.requires_ext(extension='security-group', service='network') - @utils.requires_ext(extension='router', service='network') - def skip_checks(cls): - super(TestTaaS, cls).skip_checks() - - @classmethod - def resource_setup(cls): - LOG.debug("Initializing TaaSScenarioTest Setup") - super(TestTaaS, cls).resource_setup() - LOG.debug("TaaSScenarioTest Setup done.") - - def _create_server(self, network, security_group=None): - """Create a server - - Creates a server having a port on given network and security group. - """ - keys = self.create_keypair() - kwargs = {} - if security_group is not None: - kwargs['security_groups'] = [{'name': security_group['name']}] - server = self.create_server( - key_name=keys['name'], - networks=[{'uuid': network['id']}], - wait_until='ACTIVE', - **kwargs) - return server, keys - - def _create_test_server(self, network, security_group): - """Create a server - - Creates a server having a port on given network and security group; - Also creates a floting IP if port is not an sriov port. - """ - pub_network_id = CONF.network.public_network_id - server, keys = self._create_server( - network, security_group=security_group) - private_key = keys['private_key'] - vnic_type = CONF.network.port_vnic_type - server_floating_ip = None - if vnic_type != 'direct': - server_floating_ip = self.create_floating_ip(server, - pub_network_id) - fixed_ip = list(server['addresses'].values())[0][0]['addr'] - return server, private_key, fixed_ip, server_floating_ip - - @testtools.skipUnless(CONF.taas_plugin_options.provider_physical_network, - 'Provider physical network parameter not provided.') - @utils.requires_ext(extension="provider", service="network") - def _create_network_sriov(self, networks_client=None, - tenant_id=None, - namestart='network-smoke-sriov-', - port_security_enabled=True): - if not networks_client: - networks_client = self.networks_client - if not tenant_id: - tenant_id = networks_client.tenant_id - name = data_utils.rand_name(namestart) - network_kwargs = dict(name=name, tenant_id=tenant_id) - # Neutron disables port security by default so we have to check the - # config before trying to create the network with - # port_security_enabled - if CONF.network_feature_enabled.port_security: - network_kwargs['port_security_enabled'] = port_security_enabled - - if CONF.network.port_vnic_type and \ - CONF.network.port_vnic_type == 'direct': - network_kwargs['provider:network_type'] = 'vlan' - if CONF.taas_plugin_options.provider_segmentation_id: - if CONF.taas_plugin_options.provider_segmentation_id == '0': - network_kwargs['provider:network_type'] = 'flat' - else: - network_kwargs['provider:segmentation_id'] = \ - CONF.taas_plugin_options.provider_segmentation_id - - network_kwargs['provider:physical_network'] = \ - CONF.taas_plugin_options.provider_physical_network - - result = networks_client.create_network(**network_kwargs) - network = result['network'] - self.assertEqual(network['name'], name) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - networks_client.delete_network, - network['id']) - return network - - @testtools.skipUnless(CONF.taas_plugin_options.provider_physical_network, - 'Provider physical network parameter not provided.') - @utils.requires_ext(extension="provider", service="network") - def create_networks_sriov(self, networks_client=None, - routers_client=None, subnets_client=None, - tenant_id=None, dns_nameservers=None, - port_security_enabled=True): - """Create a network with a subnet connected to a router. - - The baremetal driver is a special case since all nodes are - on the same shared network. - - :param tenant_id: id of tenant to create resources in. - :param dns_nameservers: list of dns servers to send to subnet. - :returns: network, subnet, router - """ - router = None - if CONF.network.shared_physical_network: - # NOTE(Shrews): This exception is for environments where tenant - # credential isolation is available, but network separation is - # not (the current baremetal case). Likely can be removed when - # test account mgmt is reworked: - # https://blueprints.launchpad.net/tempest/+spec/test-accounts - if not CONF.compute.fixed_network_name: - msg = 'fixed_network_name must be specified in config' - raise lib_exc.InvalidConfiguration(msg) - network = self._get_network_by_name( - CONF.compute.fixed_network_name) - subnet = None - else: - network = self._create_network_sriov( - networks_client=networks_client, - tenant_id=tenant_id, - port_security_enabled=port_security_enabled) - subnet_kwargs = dict(network=network, - subnets_client=subnets_client, - routers_client=routers_client) - # use explicit check because empty list is a valid option - if dns_nameservers is not None: - subnet_kwargs['dns_nameservers'] = dns_nameservers - subnet = self._create_subnet(**subnet_kwargs) - return network, subnet, router - - def _create_topology(self): - """Topology - - +----------+ +----------+ - | "server" | | "server" | - | VM-1 | | VM-2 | - | | | | - +----+-----+ +----+-----+ - | | - | | - +----+----+----+----+----+----+-----+ - | - | - | - +------+------+ - | "server" | - | tap-service | - +-------------+ - """ - LOG.debug('Starting Topology Creation') - resp = {} - # Create Network1 and Subnet1. - vnic_type = CONF.network.port_vnic_type - if vnic_type == 'direct': - self.network1, self.subnet1, self.router1 = \ - self.create_networks_sriov() - else: - self.network1, self.subnet1, self.router1 = self.create_networks() - resp['network1'] = self.network1 - resp['subnet1'] = self.subnet1 - resp['router1'] = self.router1 - - # Create a security group allowing icmp and ssh traffic. - security_group = self._create_security_group() - - # Create 3 VMs and assign them a floating IP each. - server1, private_key1, server_fixed_ip_1, server_floating_ip_1 = ( - self._create_test_server(self.network1, security_group)) - server2, private_key2, server_fixed_ip_2, server_floating_ip_2 = ( - self._create_test_server(self.network1, security_group)) - server3, private_key3, server_fixed_ip_3, server_floating_ip_3 = ( - self._create_test_server(self.network1, security_group)) - - # Store the received information to be used later - resp['server1'] = server1 - resp['private_key1'] = private_key1 - resp['server_fixed_ip_1'] = server_fixed_ip_1 - resp['server_floating_ip_1'] = server_floating_ip_1 - - resp['server2'] = server2 - resp['private_key2'] = private_key2 - resp['server_fixed_ip_2'] = server_fixed_ip_2 - resp['server_floating_ip_2'] = server_floating_ip_2 - - resp['server3'] = server3 - resp['private_key3'] = private_key3 - resp['server_fixed_ip_3'] = server_fixed_ip_3 - resp['server_floating_ip_3'] = server_floating_ip_3 - - return resp - - @utils.services('network') - @utils.requires_ext(extension="taas-vlan-filter", service="network") - @decorators.attr(type='slow') - @decorators.idempotent_id('40903cbd-0e3c-464d-b311-dc77d3894e65') - def test_tap_flow_data_mirroring(self): - """Create test topology and TaaS resources - - Creates test topology consisting of 3 servers, one routable network, - ports and TaaS resources, i.e. tap-service and tap-flow using those - ports. - """ - topology = self._create_topology() - - # Fetch source port and tap-service port to be used for creating - # Tap Service and Tap flow. - source_port = self.os_admin.ports_client.list_ports( - network_id=topology['network1']['id'], - device_id=topology['server1']['id'] - )['ports'][0] - - tap_service_port = self.os_admin.ports_client.list_ports( - network_id=topology['network1']['id'], - device_id=topology['server3']['id'] - )['ports'][0] - - # Create Tap-Service. - tap_service = self.create_tap_service(port_id=tap_service_port['id']) - - LOG.debug('TaaS Config options: vlan-filter: %s', - CONF.taas_plugin_options.vlan_filter) - - # Create Tap-Flow. - vnic_type = CONF.network.port_vnic_type - vlan_filter = None - if vnic_type == 'direct': - vlan_filter = '108-117,126,135-144' - if CONF.taas_plugin_options.vlan_filter: - vlan_filter = CONF.taas_plugin_options.vlan_filter - elif topology['network1']['provider:segmentation_id'] != '0': - vlan_filter = topology['network1']['provider:segmentation_id'] - - tap_flow = self.create_tap_flow(tap_service_id=tap_service['id'], - direction='BOTH', - source_port=source_port['id'], - vlan_filter=vlan_filter) - - self.assertEqual(tap_flow['vlan_filter'], vlan_filter) diff --git a/neutron_taas_tempest_plugin/tests/scenario/test_traffic_impact.py b/neutron_taas_tempest_plugin/tests/scenario/test_traffic_impact.py deleted file mode 100644 index 12dd273..0000000 --- a/neutron_taas_tempest_plugin/tests/scenario/test_traffic_impact.py +++ /dev/null @@ -1,245 +0,0 @@ -# Copyright (c) 2019 AT&T -# 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. - -from contextlib import contextmanager -from oslo_log import log -import testtools - -from tempest.common import utils -from tempest import config -from tempest.lib.common.utils.linux import remote_client -from tempest.lib import decorators - -from neutron_taas_tempest_plugin.tests.scenario import base - - -CONF = config.CONF -LOG = log.getLogger(__name__) - - -class TestTaaSTrafficScenarios(base.TaaSScenarioTest): - - @classmethod - def setup_clients(cls): - super(TestTaaSTrafficScenarios, cls).setup_clients() - - if CONF.image_feature_enabled.api_v1: - cls.image_client = cls.os_primary.image_client - elif CONF.image_feature_enabled.api_v2: - cls.image_client = cls.os_primary.image_client_v2 - else: - raise cls.skipException( - 'Either api_v1 or api_v2 must be True in ' - '[image-feature-enabled].') - - @classmethod - @utils.requires_ext(extension="router", service="network") - def resource_setup(cls): - super(TestTaaSTrafficScenarios, cls).resource_setup() - for ext in ['taas']: - if not utils.is_extension_enabled(ext, 'network'): - msg = "%s Extension not enabled." % ext - raise cls.skipException(msg) - - cls.network, cls.subnet, cls.router = cls.create_networks() - cls.provider_network = None - cls.keypair = cls.create_keypair() - cls.secgroup = cls._create_security_group() - - @contextmanager - def _setup_topology(self, taas=True, use_taas_cloud_image=False, - provider_net=False): - """Setup topology for the test - - +------------+ - | monitor vm | - +-----+------+ - | - +-----v---+ - +--+ network <--+ - | +----^----+ | - | | | - | +----+-+ +---+--+ - | | vm 1 | | vm 2 | - | +------+ +------+ - | - | +--------+ - +--> router | - +-----+--+ - | - +-----v------+ - | public net | - +------------+ - """ - if provider_net: - if CONF.taas_plugin_options.provider_physical_network: - self.provider_network = self._setup_provider_network() - else: - msg = "provider_physical_network not provided" - raise self.skipException(msg) - - self.mon_port, mon_fip = self._create_server_with_floatingip( - use_taas_cloud_image=use_taas_cloud_image, - provider_net=provider_net) - self.left_port, left_fip = self._create_server_with_floatingip( - provider_net=provider_net) - self.right_port, right_fip = self._create_server_with_floatingip( - provider_net=provider_net) - - if taas: - LOG.debug("Create TAAS service") - tap_service = self.create_tap_service(port_id=self.mon_port['id']) - self.create_tap_flow(tap_service_id=tap_service['id'], - direction='BOTH', - source_port=self.left_port['id']) - self.create_tap_flow(tap_service_id=tap_service['id'], - direction='BOTH', - source_port=self.right_port['id']) - - user = CONF.validation.image_ssh_user - if use_taas_cloud_image: - user = CONF.taas_plugin_options.advanced_image_ssh_user - - self.monitor_client = remote_client.RemoteClient( - mon_fip['floating_ip_address'], user, - pkey=self.keypair['private_key']) - self.left_client = remote_client.RemoteClient( - left_fip['floating_ip_address'], CONF.validation.image_ssh_user, - pkey=self.keypair['private_key']) - self.right_client = remote_client.RemoteClient( - right_fip['floating_ip_address'], CONF.validation.image_ssh_user, - pkey=self.keypair['private_key']) - yield - - def _check_icmp_traffic(self): - log_location = "/tmp/tcpdumplog" - - right_ip = self.right_port['fixed_ips'][0]['ip_address'] - left_ip = self.left_port['fixed_ips'][0]['ip_address'] - - # Run tcpdump in background - self._run_in_background(self.monitor_client, - "sudo tcpdump -n -nn > %s" % log_location) - - # Ensure tcpdump is up and running - psax = self.monitor_client.exec_command("ps -ax") - self.assertTrue("tcpdump" in psax) - - # Run traffic from left_vm to right_vm - self.left_client.exec_command("ping -c 50 %s" % right_ip) - - # Collect tcpdump results - output = self.monitor_client.exec_command("cat %s" % log_location) - self.assertTrue(len(output) > 0) - - looking_for = ["IP %s > %s: ICMP echo request" % (left_ip, right_ip), - "IP %s > %s: ICMP echo reply" % (right_ip, left_ip)] - - results = [] - for tcpdump_line in looking_for: - results.append(tcpdump_line in output) - - return all(results) - - def _test_taas_connectivity(self, use_provider_net=False): - """Ensure TAAS doesn't break connectivity - - This test creates TAAS service between two servers and checks that - it doesn't break basic connectivity between them. - """ - - # Check uninterrupted traffic between VMs - with self._setup_topology(provider_net=use_provider_net): - # Left to right - self._check_remote_connectivity( - self.left_client, - self.right_port['fixed_ips'][0]['ip_address']) - - # Right to left - self._check_remote_connectivity( - self.right_client, - self.left_port['fixed_ips'][0]['ip_address']) - - # TAAS vm to right - self._check_remote_connectivity( - self.monitor_client, - self.right_port['fixed_ips'][0]['ip_address']) - - # TAAS vm to left - self._check_remote_connectivity( - self.monitor_client, - self.left_port['fixed_ips'][0]['ip_address']) - - @decorators.idempotent_id('ff414b7d-e81c-47f2-b6c8-53bc2f1e9b00') - @decorators.attr(type='slow') - @utils.services('compute', 'network') - def test_taas_provider_network_connectivity(self): - self._test_taas_connectivity(use_provider_net=True) - - @decorators.idempotent_id('e3c52e91-7abf-4dfd-8687-f7c071cdd333') - @decorators.attr(type='slow') - @utils.services('compute', 'network') - def test_taas_network_connectivity(self): - self._test_taas_connectivity(use_provider_net=False) - - @decorators.idempotent_id('fcb15ca3-ef61-11e9-9792-f45c89c47e11') - @testtools.skipUnless(CONF.taas_plugin_options.advanced_image_ref, - 'Cloud image not found.') - @decorators.attr(type='slow') - @utils.services('compute', 'network') - def test_taas_forwarded_traffic_positive(self): - """Check that TAAS forwards traffic as expected""" - - with self._setup_topology(use_taas_cloud_image=True): - # Check that traffic was forwarded to TAAS service - self.assertTrue(self._check_icmp_traffic()) - - @decorators.idempotent_id('6c54d9c5-075a-4a1f-bbe6-12c3c9abf1e2') - @testtools.skipUnless(CONF.taas_plugin_options.advanced_image_ref, - 'Cloud image not found.') - @decorators.attr(type='slow') - @utils.services('compute', 'network') - def test_taas_forwarded_traffic_negative(self): - """Check that TAAS doesn't forward traffic""" - - with self._setup_topology(taas=False, use_taas_cloud_image=True): - # Check that traffic was NOT forwarded to TAAS service - self.assertFalse(self._check_icmp_traffic()) - - @decorators.idempotent_id('fcb15ca3-ef61-11e9-9792-f45c89c47e12') - @testtools.skipUnless(CONF.taas_plugin_options.advanced_image_ref, - 'Cloud image not found.') - @decorators.attr(type='slow') - @utils.services('compute', 'network') - def test_taas_forwarded_traffic_provider_net_positive(self): - """Check that TAAS forwards traffic as expected in provider network""" - - with self._setup_topology(use_taas_cloud_image=True, - provider_net=True): - # Check that traffic was forwarded to TAAS service - self.assertTrue(self._check_icmp_traffic()) - - @decorators.idempotent_id('6c54d9c5-075a-4a1f-bbe6-12c3c9abf1e3') - @testtools.skipUnless(CONF.taas_plugin_options.advanced_image_ref, - 'Cloud image not found.') - @decorators.attr(type='slow') - @utils.services('compute', 'network') - def test_taas_forwarded_traffic_provider_net_negative(self): - """Check that TAAS doesn't forward traffic in provider network""" - - with self._setup_topology(taas=False, use_taas_cloud_image=True, - provider_net=True): - # Check that traffic was NOT forwarded to TAAS service - self.assertFalse(self._check_icmp_traffic()) diff --git a/neutron_taas_tempest_plugin/tests/taas_client.py b/neutron_taas_tempest_plugin/tests/taas_client.py deleted file mode 100644 index f5c7dc3..0000000 --- a/neutron_taas_tempest_plugin/tests/taas_client.py +++ /dev/null @@ -1,84 +0,0 @@ -# Copyright (c) 2015 Midokura SARL -# 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. - -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils - -from neutron_taas_tempest_plugin.services import client - -CONF = config.CONF - - -class TaaSClientMixin(object): - - @classmethod - def resource_setup(cls): - super(TaaSClientMixin, cls).resource_setup() - os_primary = cls.os_primary - cls.tap_services_client = 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 = 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/requirements.txt b/requirements.txt deleted file mode 100644 index 040cd0e..0000000 --- a/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. - -pbr>=5.5.0 # Apache-2.0 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 9d9846e..0000000 --- a/setup.cfg +++ /dev/null @@ -1,45 +0,0 @@ -[metadata] -name = tap-as-a-service-tempest-plugin -summary = Tempest plugin for Tap-as-a-Service -description-file = - README.rst -author = OpenStack -author-email = openstack-discuss@lists.openstack.org -home-page = http://www.openstack.org/ -classifier = - Environment :: OpenStack - Intended Audience :: Information Technology - Intended Audience :: System Administrators - License :: OSI Approved :: Apache Software License - Operating System :: POSIX :: Linux - Programming Language :: Python - Programming Language :: Python :: 2 - Programming Language :: Python :: 2.7 - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.5 - -[files] -packages = - neutron_taas_tempest_plugin - -[build_sphinx] -source-dir = doc/source -build-dir = doc/build -all_files = 1 - -[upload_sphinx] -upload-dir = doc/build/html - -[build_releasenotes] -build-dir = releasenotes/build -source-dir = releasenotes/source -all_files = 1 - -[entry_points] -tempest.test_plugins = - tap-as-a-service-tempest-plugin = neutron_taas_tempest_plugin.plugin:NeutronTaaSPlugin - -[pbr] -autodoc_index_modules = True -warnerrors = True - diff --git a/setup.py b/setup.py deleted file mode 100644 index 566d844..0000000 --- a/setup.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# -# 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. - -# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT -import setuptools - -# In python < 2.7.4, a lazy loading of package `pbr` will break -# setuptools if some other modules registered functions in `atexit`. -# solution from: http://bugs.python.org/issue15881#msg170215 -try: - import multiprocessing # noqa -except ImportError: - pass - -setuptools.setup( - setup_requires=['pbr>=2.0.0'], - pbr=True) diff --git a/test-requirements.txt b/test-requirements.txt deleted file mode 100644 index cdfaa11..0000000 --- a/test-requirements.txt +++ /dev/null @@ -1,13 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. - -hacking>=3.0.0,<3.1 # Apache-2.0 - -coverage>=5.2.1 # Apache-2.0 -python-subunit>=1.4.0 # Apache-2.0/BSD -sphinx!=1.6.6,!=1.6.7,>=1.6.2 # BSD -oslosphinx>=4.7.0 # Apache-2.0 -oslotest>=4.4.1 # Apache-2.0 -os-testr>=1.0.0 # Apache-2.0 -reno>=2.5.0 # Apache-2.0 diff --git a/tox.ini b/tox.ini deleted file mode 100644 index a9df05d..0000000 --- a/tox.ini +++ /dev/null @@ -1,34 +0,0 @@ -[tox] -envlist = pep8 -minversion = 1.8 -skipsdist = True - -[testenv] -setenv = VIRTUAL_ENV={envdir} - PYTHONWARNINGS=default::DeprecationWarning -usedevelop = True -install_command = pip install {opts} {packages} -deps = -c{env:UPPER_CONSTRAINTS_FILE:https://opendev.org/openstack/requirements/raw/branch/master/upper-constraints.txt} - -r{toxinidir}/requirements.txt - -r{toxinidir}/test-requirements.txt -commands = find . -type f -name "*.py[c|o]" -delete - find . -type l -name "*.py[c|o]" -delete - find . -type d -name "__pycache__" -delete - ostestr --regex '{posargs}' -whitelist_externals = find - -[testenv:pep8] -commands = - flake8 - -[testenv:venv] -commands = {posargs} - -[flake8] -# E123, E125 skipped as they are invalid PEP-8. -# W504 Line break occurred after a binary operator - -show-source = True -ignore = E123,E125,W504 -builtins = _ -exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build