Remove stuff not necessary for the tempest plugin

This commit is contained in:
YAMAMOTO Takashi 2019-03-27 17:44:46 +09:00
parent 9e8299246b
commit 05fe7a96d1
115 changed files with 17 additions and 5698 deletions

View File

@ -1,3 +0,0 @@
[DEFAULT]
test_path=${OS_TEST_PATH:-./neutron_taas/tests/unit}
top_dir=./

View File

@ -1,7 +0,0 @@
[DEFAULT]
test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \
${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./neutron_taas/tests/unit} $LISTOPT $IDOPTION
test_id_option=--load-list $IDFILE
test_list_option=--list

View File

@ -1,27 +1,4 @@
- project:
check:
jobs:
- tap-as-a-service-tempest-dsvm
- openstack-tox-lower-constraints
gate:
jobs:
- tap-as-a-service-tempest-dsvm
- openstack-tox-lower-constraints
- job:
name: tap-as-a-service-tempest-dsvm
parent: legacy-dsvm-base
run: playbooks/legacy/tempest-dsvm-tap-as-a-service/run.yaml
post-run: playbooks/legacy/tempest-dsvm-tap-as-a-service/post.yaml
timeout: 7800
required-projects:
- openstack-infra/devstack-gate
- openstack/tap-as-a-service
- openstack/tempest
irrelevant-files:
- ^(test-|)requirements.txt$
- ^.*\.rst$
- ^doc/.*$
- ^neutron_taas/tests/unit/.*$
- ^setup.cfg$
- ^specs/.*$
templates:
- check-requirements
- tempest-plugin-jobs

View File

@ -1,277 +0,0 @@
==============================
Tap as a Service API REFERENCE
==============================
This documents is an API REFERENCE for Tap-as-a-Service Neutron extension.
The documents is organized into the following sections:
* TaaS Resources
* API Reference
* TaaS CLI Reference
* Workflow
TaaS Resources
==============
TaaS consists of two resources, TapService and TapFlow.
TapService
----------
TapService Represents the port on which the mirrored traffic is delivered.
Any service (VM) that uses the mirrored data is attached to the port.
.. code-block:: python
'tap_services': {
'id': {'allow_post': False, 'allow_put': False,
'validate': {'type:uuid': None}, 'is_visible': True,
'primary_key': True},
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True, 'is_visible': True},
'name': {'allow_post': True, 'allow_put': True,
'validate': {'type:string': None},
'is_visible': True, 'default': ''},
'description': {'allow_post': True, 'allow_put': True,
'validate': {'type:string': None},
'is_visible': True, 'default': ''},
'port_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:uuid': None},
'is_visible': True},
}
TapFlow
-------
TapFlow Represents the port from which the traffic needs to be mirrored.
.. code-block:: python
'tap_flows': {
'id': {'allow_post': False, 'allow_put': False,
'validate': {'type:uuid': None}, 'is_visible': True,
'primary_key': True},
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True, 'is_visible': True},
'name': {'allow_post': True, 'allow_put': True,
'validate': {'type:string': None},
'is_visible': True, 'default': ''},
'description': {'allow_post': True, 'allow_put': True,
'validate': {'type:string': None},
'is_visible': True, 'default': ''},
'tap_service_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:uuid': None},
'required_by_policy': True, 'is_visible': True},
'source_port': {'allow_post': True, 'allow_put': False,
'validate': {'type:uuid': None},
'required_by_policy': True, 'is_visible': True},
'direction': {'allow_post': True, 'allow_put': False,
'validate': {'type:values': direction_enum},
'is_visible': True}
}
direction_enum = ['IN', 'OUT', 'BOTH']
Multiple TapFlow instances can be associated with a single TapService
instance.
API REFERENCE
=============
Below is the list of REST APIs that can be used to interact with TaaS Neutron
extension
1. Create TapService
\
**POST /v2.0/taas/tap_services**
\
Json Request:
.. code-block:: python
{
"tap_service": {
"description": "Test_Tap",
"name": "Test",
"port_id": "c9beb5a1-21f5-4225-9eaf-02ddccdd50a9",
"tenant_id": "97e1586d580745d7b311406697aaf097"
}
}
\
Json Response:
.. code-block:: python
{
"tap_service": {
"description": "Test_Tap",
"id": "c352f537-ad49-48eb-ab05-1c6b8cb900ff",
"name": "Test",
"port_id": "c9beb5a1-21f5-4225-9eaf-02ddccdd50a9",
"tenant_id": "97e1586d580745d7b311406697aaf097"
}
}
2. List TapServices
\
**GET /v2.0/taas/tap_services/{tap_service_uuid}**
\
Json Response:
.. code-block:: python
{
"tap_services": [
{
"description": "Test_Tap",
"id": "c352f537-ad49-48eb-ab05-1c6b8cb900ff",
"name": "Test",
"port_id": "c9beb5a1-21f5-4225-9eaf-02ddccdd50a9",
"tenant_id": "97e1586d580745d7b311406697aaf097"
}
]
}
3. Delete TapService
\
**DELETE /v2.0/taas/tap_services/{tap_service_uuid}**
\
4. Create TapFlow
\
**POST /v2.0/taas/tap_flows**
\
Json Request:
.. code-block:: python
{
"tap_flow": {
"description": "Test_flow1",
"direction": "BOTH",
"name": "flow1",
"source_port": "775a58bb-e2c6-4529-a918-2f019169b5b1",
"tap_service_id": "69bd12b2-0e13-45ec-9045-b674fd9f0468",
"tenant_id": "97e1586d580745d7b311406697aaf097"
}
}
\
Json Response:
.. code-block:: python
{
"tap_flow": {
"description": "Test_flow1",
"direction": "BOTH",
"id": "cc47f881-345f-4e62-ad24-bea79eb28304",
"name": "flow1",
"source_port": "775a58bb-e2c6-4529-a918-2f019169b5b1",
"tap_service_id": "69bd12b2-0e13-45ec-9045-b674fd9f0468",
"tenant_id": "97e1586d580745d7b311406697aaf097"
}
}
5. List TapFlows
\
**GET /v2.0/taas/tap_flows/{tap_flow_uuid}**
\
Json Response:
.. code-block:: python
{
"tap_flows": [
{
"description": "Test_flow1",
"direction": "BOTH",
"id": "cc47f881-345f-4e62-ad24-bea79eb28304",
"name": "flow1",
"source_port": "775a58bb-e2c6-4529-a918-2f019169b5b1",
"tap_service_id": "c352f537-ad49-48eb-ab05-1c6b8cb900ff",
"tenant_id": "97e1586d580745d7b311406697aaf097"
}
]
}
6. Delete TapFlow
\
**DELETE /v2.0/taas/tap_flows/{tap_flow_uuid}**
\
TaaS CLI Reference
==================
The TaaS commands can be executed using TaaS CLI, which is integrated with neutron.
It can be used to send REST request and interact with the TaaS
extension. Given below are the detail of the CLIs:
- **neutron tap-service-create**: Creates a Tap service.
- **neutron tap-service-list**: Lists all the Tap services.
- **neutron tap-service-show**: Show the details for a Tap service.
- **neutron tap-service-update**: Update the information for a Tap service.
- **neutron tap-service-delete**: Delete an existing Tap service.
- **neutron tap-flow-create**: Creates a Tap flow.
- **neutron tap-flow-list**: Lists all the Tap flows.
- **neutron tap-flow-show**: Show the details for a Tap flow.
- **neutron tap-flow-update**: Update the information for a Tap flow.
- **neutron tap-flow-delete**: Delete an existing Tap flow.
For usage type **--help** after any of the above commands
in the terminal after TaaS has been installed.
Workflow
=========
In this section we describe a simple sequence of steps to use TaaS.
Workflow Sequence
------------------
1. Create a Neutron port with 'port_security_enabled' set to 'false'.
2. Launch a VM (VM on which you want to monitor/receive the mirrored data).
Associate the Neutron port created in step 1 while creating the VM.
3. Using Neutron Client command for TaaS **neutron tap-service-create** or
via REST APIs create a Tap Service instance by associating the port
created in step 1.
4. Using Neutron Client command for TaaS **neutron tap-flow-create** or
via REST APIs create a Tap Flow instance by associating the Tap Service
instance created in step 3 and the target Neutron port from which you want
to mirror traffic (assuming the Neutron port from which the traffic
needs to be monitored already exists.)
Mirroring can be done for both incoming and/or outgoing traffic from the
target Neutron port.
5. Observe the mirrored traffic on the monitoring VM by running tools such as
tcpdump.

View File

@ -1,4 +0,0 @@
tap-as-a-service Style Commandments
===============================================
Read the OpenStack Style Commandments https://docs.openstack.org/hacking/latest/

View File

@ -1,29 +0,0 @@
===================================
Tap as a Service installation guide
===================================
This is the installation guide for enabling Tap-as-a-Service(TaaS) feature in
OpenStack Neutron
We have tested TaaS with latest version DevStack running on Ubuntu 12.04 and
14.04. TaaS is currently under active development and we will update you of
new features and capabilities as and when they become available. Feel free to
approach us with any issues related to installing or using TaaS.
Dependencies
============
TaaS requires the 'Port Security' Neutron ML2 extension. Please make sure that
this extension has been enabled.
Adding the following to 'local.conf' while installing DevStack will enable
'Port Security' extension. (It's enabled by default)
Q_ML2_PLUGIN_EXT_DRIVERS=port_security
Installation
============
You can use DevStack external plugin.
See `devstack/README.rst`.

View File

@ -1,24 +1,5 @@
================
Tap as a Service
================
Tap-as-a-Service (TaaS) is an extension to the OpenStack network service (Neutron).
It provides remote port mirroring capability for tenant virtual networks.
===================================
Tempest plugin for Tap as a Service
===================================
Port mirroring involves sending a copy of packets entering and/or leaving one
port to another port, which is usually different from the original destinations
of the packets being mirrored.
This service has been primarily designed to help tenants (or the cloud administrator)
debug complex virtual networks and gain visibility into their VMs, by monitoring the
network traffic associated with them. TaaS honors tenant boundaries and its mirror
sessions are capable of spanning across multiple compute and network nodes. It serves
as an essential infrastructure component that can be utilized for supplying data to a
variety of network analytics and security applications (e.g. IDS).
* Free software: Apache license
* API Reference: https://github.com/openstack/tap-as-a-service/blob/master/API_REFERENCE.rst
* Source: https://git.openstack.org/cgit/openstack/tap-as-a-service
* Bugs: https://bugs.launchpad.net/tap-as-a-service
For installing Tap-as-a-Service with Devstack please read the INSTALL.rst file
This repository contains tempest plugin for tap-as-a-service.

View File

@ -1,2 +0,0 @@
[python: **.py]

View File

@ -1,11 +0,0 @@
---
launchpad: tap-as-a-service
type: other
releases:
- projects:
- hash: e528a0ba81f24d0da178bbfac94d517f664aa149
repo: openstack/tap-as-a-service
version: 3.0.0
branches:
- name: stable/queens
location: 3.0.0

View File

@ -1,11 +0,0 @@
---
launchpad: tap-as-a-service
type: other
releases:
- projects:
- hash: 57dfbdb8ebbf8d42d0715f7753626ed2ddf38cef
repo: openstack/tap-as-a-service
version: 4.0.0
branches:
- name: stable/rocky
location: 4.0.0

View File

@ -1,10 +0,0 @@
========================
DevStack external plugin
========================
A `local.conf` recipe to enable tap-as-a-service::
[[local|localrc]]
enable_plugin tap-as-a-service https://github.com/openstack/tap-as-a-service
enable_service taas
TAAS_SERVICE_DRIVER=TAAS:TAAS:neutron_taas.services.taas.service_drivers.taas_rpc.TaasRpcDriver:default

View File

@ -1,42 +0,0 @@
# Copyright 2015 Midokura SARL
#
# 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 script is executed in the OpenStack CI job that runs DevStack + tempest.
# You can find the CI job configuration here:
#
# http://git.openstack.org/cgit/openstack-infra/project-config/tree/jenkins/jobs/tap-as-a-service.yaml
#
OVERRIDE_ENABLED_SERVICES=key,mysql,rabbit
OVERRIDE_ENABLED_SERVICES+=,g-api,g-reg
OVERRIDE_ENABLED_SERVICES+=,n-api,n-cond,n-cpu,n-crt,n-sch,placement-api
OVERRIDE_ENABLED_SERVICES+=,n-api-meta
OVERRIDE_ENABLED_SERVICES+=,q-agt,q-dhcp,q-l3,q-meta,q-metering,q-svc,quantum
OVERRIDE_ENABLED_SERVICES+=,taas,taas_openvswitch_agent
OVERRIDE_ENABLED_SERVICES+=,tempest,dstat
export OVERRIDE_ENABLED_SERVICES
# Begin list of exclusions.
r="^(?!.*"
# exclude the slow tag (part of the default for 'full')
r="$r(?:.*\[.*\bslow\b.*\])"
# End list of exclusions.
r="$r)"
r="$r(tempest\.(api.network\.|scenario.test_network)|neutron_taas\.).*$"
export DEVSTACK_GATE_TEMPEST_REGEX="$r"

View File

@ -1,71 +0,0 @@
#!/bin/bash
# Copyright 2015 Midokura SARL
#
# 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 script is meant to be sourced from devstack. It is a wrapper of
# devmido scripts that allows proper exporting of environment variables.
function install_taas {
setup_develop $TAAS_PLUGIN_PATH
}
function configure_taas_plugin {
cp $TAAS_PLUGIN_PATH/etc/taas_plugin.ini $TAAS_PLUGIN_CONF_FILE
neutron_server_config_add $TAAS_PLUGIN_CONF_FILE
neutron_service_plugin_class_add taas
}
if is_service_enabled taas; then
if [[ "$1" == "stack" ]]; then
if [[ "$2" == "pre-install" ]]; then
:
elif [[ "$2" == "install" ]]; then
install_taas
elif [[ "$2" == "post-config" ]]; then
configure_taas_plugin
neutron-db-manage --subproject tap-as-a-service upgrade head
echo "Configuring taas"
if [ "$TAAS_SERVICE_DRIVER" ]; then
inicomment $TAAS_PLUGIN_CONF_FILE service_providers service_provider
iniadd $TAAS_PLUGIN_CONF_FILE service_providers service_provider $TAAS_SERVICE_DRIVER
fi
elif [[ "$2" == "extra" ]]; then
:
fi
elif [[ "$1" == "unstack" ]]; then
:
fi
fi
if is_service_enabled q-agt neutron-agent; then
if [[ "$1" == "stack" ]]; then
if [[ "$2" == "pre-install" ]]; then
:
elif [[ "$2" == "install" ]]; then
install_taas
elif [[ "$2" == "post-config" ]]; then
if is_service_enabled q-agt neutron-agent; then
source $NEUTRON_DIR/devstack/lib/l2_agent
plugin_agent_add_l2_agent_extension taas
configure_l2_agent
fi
elif [[ "$2" == "extra" ]]; then
:
fi
elif [[ "$1" == "unstack" ]]; then
:
fi
fi

View File

@ -1,6 +0,0 @@
# Devstack settings
ABSOLUTE_PATH=$(cd `dirname "${BASH_SOURCE[0]}"` && pwd)
TAAS_PLUGIN_PATH=$ABSOLUTE_PATH/..
TAAS_PLUGIN_CONF_FILE="/etc/neutron/taas_plugin.ini"
TAAS_OVS_AGENT_BINARY="$NEUTRON_BIN_DIR/neutron-taas-openvswitch-agent"
TAAS_OVS_AGENT_CONF_FILE="/etc/neutron/taas.ini"

View File

@ -1 +0,0 @@
.. include:: ../../API_REFERENCE.rst

View File

@ -1,75 +0,0 @@
# -*- coding: utf-8 -*-
# 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
import sys
sys.path.insert(0, os.path.abspath('../..'))
# -- General configuration ----------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = [
'sphinx.ext.autodoc',
#'sphinx.ext.intersphinx',
'oslosphinx'
]
# autodoc generation is a bit aggressive and a nuisance when doing heavy
# text edit cycles.
# execute "export SPHINX_DEBUG=1" in your terminal to disable
# The suffix of source filenames.
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'tap-as-a-service'
copyright = u'2013, OpenStack Foundation'
# If true, '()' will be appended to :func: etc. cross-reference text.
add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
add_module_names = True
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# -- Options for HTML output --------------------------------------------------
# The theme to use for HTML and HTML Help pages. Major themes that come with
# Sphinx are currently 'default' and 'sphinxdoc'.
# html_theme_path = ["."]
# html_theme = '_theme'
# html_static_path = ['static']
# Output file base name for HTML help builder.
htmlhelp_basename = '%sdoc' % project
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass
# [howto/manual]).
latex_documents = [
('index',
'%s.tex' % project,
u'%s Documentation' % project,
u'OpenStack Foundation', 'manual'),
]
# Example configuration for intersphinx: refer to the Python standard library.
#intersphinx_mapping = {'http://docs.python.org/': None}

View File

@ -1,4 +0,0 @@
============
Contributing
============
.. include:: ../../CONTRIBUTING.rst

View File

@ -1,27 +0,0 @@
.. tap-as-a-service documentation master file, created by
sphinx-quickstart on Tue Jul 9 22:26:36 2013.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to tap-as-a-service's documentation!
========================================================
Contents:
.. toctree::
:maxdepth: 2
readme
installation
api_reference
contributing
specs/index
presentations
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

View File

@ -1 +0,0 @@
.. include:: ../../INSTALL.rst

View File

@ -1,21 +0,0 @@
=============
Presentations
=============
- `Tap-As-A-Service What You Need to Know Now
<https://www.openstack.org/videos/video/tap-as-a-service-what-you-need-to-know-now>`_
40 min presentation at OpenStack Summit Austin, April 2016,
including a demo with Horizon.
- `Using Open Source Security Architecture to Defend against Targeted Attacks`
<https://www.openstack.org/videos/video/using-open-source-security-architecture-to-defend-against-targeted-attacks>
40 min presentation at OpenStack Summit Austin, April 2016,
including IDS/IPS use cases and a demo with snort.
- `Tap-as-a-Service (TaaS): Port Monitoring for Neutron Networks
<https://www.openstack.org/summit/vancouver-2015/summit-videos/presentation/tap-as-a-service-taas-port-monitoring-for-neutron-networks>`_
40 min presentation at OpenStack Summit Vancouver, May 2015,
including a demo.

View File

@ -1 +0,0 @@
.. include:: ../../README.rst

View File

@ -1 +0,0 @@
../../specs

View File

@ -1,5 +0,0 @@
[taas]
driver = neutron_taas.services.taas.drivers.linux.ovs_taas.OvsTaasDriver
enabled = True
vlan_range_start = 3000
vlan_range_end = 3500

View File

@ -1,7 +0,0 @@
[DEFAULT]
[service_providers]
# Defines providers for advanced services using the format:
# <service_type>:<name>:<driver>[:default] (multi valued)
service_provider = TAAS:TAAS:neutron_taas.services.taas.service_drivers.taas_rpc.TaasRpcDriver:default

View File

@ -1,148 +0,0 @@
alabaster==0.7.10
alembic==0.9.8
amqp==2.2.2
appdirs==1.4.3
Babel==2.3.4
beautifulsoup4==4.6.0
cachetools==2.0.1
certifi==2018.1.18
cffi==1.11.5
chardet==3.0.4
cliff==2.11.0
cmd2==0.8.1
contextlib2==0.5.5
coverage==4.0
debtcollector==1.19.0
decorator==4.2.1
deprecation==2.0
docutils==0.14
dogpile.cache==0.6.5
dulwich==0.19.0
enum-compat==0.0.2
eventlet==0.20.0
extras==1.0.0
fasteners==0.14.1
fixtures==3.0.0
flake8==2.5.5
future==0.16.0
futurist==1.6.0
greenlet==0.4.13
hacking==0.12.0
httplib2==0.10.3
idna==2.6
imagesize==1.0.0
iso8601==0.1.12
Jinja2==2.10
jmespath==0.9.3
jsonpatch==1.21
jsonpointer==2.0
jsonschema==2.6.0
keystoneauth1==3.4.0
keystonemiddleware==4.21.0
kombu==4.1.0
linecache2==1.0.0
logutils==0.3.5
Mako==1.0.7
MarkupSafe==1.0
mccabe==0.2.1
mock==2.0.0
monotonic==1.4
mox3==0.25.0
msgpack-python==0.5.6
msgpack==0.5.6
munch==2.2.0
netaddr==0.7.19
netifaces==0.10.6
neutron-lib==1.20.0
openstacksdk==0.12.0
os-client-config==1.29.0
os-service-types==1.2.0
os-testr==1.0.0
os-xenapi==0.3.1
osc-lib==1.10.0
oslo.cache==1.29.0
oslo.concurrency==3.26.0
oslo.config==5.2.0
oslo.context==2.20.0
oslo.db==4.35.0
oslo.i18n==3.20.0
oslo.log==3.37.0
oslo.messaging==5.36.0
oslo.middleware==3.35.0
oslo.policy==1.34.0
oslo.privsep==1.28.0
oslo.reports==1.27.0
oslo.rootwrap==5.13.0
oslo.serialization==2.25.0
oslo.service==1.30.0
oslo.utils==3.36.0
oslo.versionedobjects==1.32.0
oslosphinx==4.7.0
oslotest==3.2.0
osprofiler==2.0.0
ovs==2.8.1
ovsdbapp==0.10.0
packaging==17.1
Paste==2.0.3
PasteDeploy==1.5.2
pbr==2.0.0
pecan==1.2.1
pep8==1.5.7
pika-pool==0.1.3
pika==0.10.0
prettytable==0.7.2
psutil==5.4.3
psycopg2==2.6.2
pycadf==2.7.0
pycparser==2.18
pyflakes==0.8.1
Pygments==2.2.0
pyinotify==0.9.6
PyMySQL==0.7.6
pyparsing==2.2.0
pyperclip==1.6.0
pyroute2==0.4.21
python-dateutil==2.7.0
python-designateclient==2.9.0
python-editor==1.0.3
python-keystoneclient==3.15.0
python-mimeparse==1.6.0
python-neutronclient==6.7.0
python-novaclient==10.1.0
python-subunit==1.0.0
pytz==2018.3
PyYAML==3.12
reno==2.5.0
repoze.lru==0.7
requests==2.18.4
requestsexceptions==1.4.0
rfc3986==1.1.0
Routes==2.4.1
ryu==4.23
simplejson==3.13.2
six==1.11.0
snowballstemmer==1.2.1
Sphinx==1.6.2
sphinxcontrib-websupport==1.0.1
sqlalchemy-migrate==0.11.0
SQLAlchemy==1.2.5
sqlparse==0.2.4
statsd==3.2.2
stestr==2.0.0
stevedore==1.28.0
Tempita==0.5.2
tenacity==4.9.0
testrepository==0.0.20
testresources==2.0.0
testscenarios==0.4
testtools==2.2.0
tinyrpc==0.8
traceback2==1.4.0
unittest2==1.1.0
urllib3==1.22
vine==1.1.4
voluptuous==0.11.1
waitress==1.1.0
WebOb==1.7.4
WebTest==2.0.29
wrapt==1.10.11

View File

@ -1,31 +0,0 @@
# 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 oslo_i18n
DOMAIN = 'neutron_taas'
_translators = oslo_i18n.TranslatorFactory(domain=DOMAIN)
# The primary translation function using the well-known name "_"
_ = _translators.primary
# The contextual translation function using the name "_C"
_C = _translators.contextual_form
# The plural translation function using the name "_P"
_P = _translators.plural_form
def get_available_languages():
return oslo_i18n.get_available_languages(DOMAIN)

View File

@ -1,16 +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.
TAAS = 'TAAS'

View File

@ -1,19 +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.
# TODO(yamamoto): Move these to neutron.common.topics
TAAS_PLUGIN = 'n-taas-plugin'
TAAS_AGENT = 'n-taas_agent'

View File

@ -1,21 +0,0 @@
# Copyright 2016 VMware, Inc
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from neutron.db.migration.models import head
from neutron_taas.db import taas_db # noqa
def get_metadata():
return head.model_base.BASEV2.metadata

View File

@ -1 +0,0 @@
Generic single-database configuration.

View File

@ -1,87 +0,0 @@
# Copyright 2015 Midokura SARL
#
# 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 logging import config as logging_config
from neutron_lib.db import model_base
from alembic import context
from oslo_config import cfg
from oslo_db.sqlalchemy import session
import sqlalchemy as sa
from sqlalchemy import event
MYSQL_ENGINE = None
TAAS_VERSION_TABLE = 'alembic_version_taas'
config = context.config
neutron_config = config.neutron_config
logging_config.fileConfig(config.config_file_name)
target_metadata = model_base.BASEV2.metadata
def set_mysql_engine():
try:
mysql_engine = neutron_config.command.mysql_engine
except cfg.NoSuchOptError:
mysql_engine = None
global MYSQL_ENGINE
MYSQL_ENGINE = (mysql_engine or
model_base.BASEV2.__table_args__['mysql_engine'])
def run_migrations_offline():
set_mysql_engine()
kwargs = dict()
if neutron_config.database.connection:
kwargs['url'] = neutron_config.database.connection
else:
kwargs['dialect_name'] = neutron_config.database.engine
kwargs['version_table'] = TAAS_VERSION_TABLE
context.configure(**kwargs)
with context.begin_transaction():
context.run_migrations()
@event.listens_for(sa.Table, 'after_parent_attach')
def set_storage_engine(target, parent):
if MYSQL_ENGINE:
target.kwargs['mysql_engine'] = MYSQL_ENGINE
def run_migrations_online():
set_mysql_engine()
engine = session.create_engine(neutron_config.database.connection)
connection = engine.connect()
context.configure(
connection=connection,
target_metadata=target_metadata,
version_table=TAAS_VERSION_TABLE
)
try:
with context.begin_transaction():
context.run_migrations()
finally:
connection.close()
engine.dispose()
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()

View File

@ -1,21 +0,0 @@
"""${message}
Revision ID: ${up_revision}
Revises: ${down_revision}
Create Date: ${create_date}
"""
# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}
% if branch_labels:
branch_labels = ${repr(branch_labels)}
%endif
from alembic import op
import sqlalchemy as sa
${imports if imports else ""}
def upgrade():
${upgrades if upgrades else "pass"}

View File

@ -1,32 +0,0 @@
# Copyright (c) 2016 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.
"""Remove network-id from tap-service
Revision ID: 1817af933379
Revises: 80c85b675b6e
Create Date: 2016-04-05 21:59:28.829793
"""
# revision identifiers, used by Alembic.
revision = '1817af933379'
down_revision = '80c85b675b6e'
from alembic import op
def upgrade():
op.drop_column('tap_services', 'network_id')

View File

@ -1,37 +0,0 @@
# Copyright 2016 Midokura SARL
#
# 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.
"""add foreign key constraint on tap id association
Revision ID: 2ecce0368a62
Revises: 1817af933379
Create Date: 2016-05-19 11:39:52.892610
"""
# revision identifiers, used by Alembic.
revision = '2ecce0368a62'
down_revision = '1817af933379'
from alembic import op
def upgrade():
op.create_foreign_key(
constraint_name=None,
source_table='tap_id_associations',
referent_table='tap_services',
local_cols=['tap_service_id'],
remote_cols=['id'],
ondelete='CASCADE')

View File

@ -1,123 +0,0 @@
# Copyright 2016 OpenStack Foundation
#
# 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.
#
"""rename tenant to project
Revision ID: 4086b3cffc01
Revises: 2ecce0368a62
Create Date: 2016-07-30 22:09:16.372917
"""
# revision identifiers, used by Alembic.
revision = '4086b3cffc01'
down_revision = '2ecce0368a62'
from alembic import op
import sqlalchemy as sa
from sqlalchemy.engine import reflection
from neutron.db import migration
_INSPECTOR = None
# milestone identifier, used by neutron-db-manage
neutron_milestone = [migration.NEWTON, migration.OCATA]
def get_inspector():
"""Reuse inspector."""
global _INSPECTOR
if _INSPECTOR:
return _INSPECTOR
else:
bind = op.get_bind()
_INSPECTOR = reflection.Inspector.from_engine(bind)
return _INSPECTOR
def get_tables():
"""Returns hardcoded list of tables which have ``tenant_id`` column.
The list is hard-coded to match the state of the schema when this upgrade
script is run.
"""
tables = [
'tap_services',
'tap_flows',
]
return tables
def get_columns(table):
"""Returns list of columns for given table."""
inspector = get_inspector()
return inspector.get_columns(table)
def get_data():
"""Returns combined list of tuples: [(table, column)].
The list is built from tables with a tenant_id column.
"""
output = []
tables = get_tables()
for table in tables:
columns = get_columns(table)
for column in columns:
if column['name'] == 'tenant_id':
output.append((table, column))
return output
def alter_column(table, column):
old_name = 'tenant_id'
new_name = 'project_id'
op.alter_column(
table_name=table,
column_name=old_name,
new_column_name=new_name,
existing_type=column['type'],
existing_nullable=column['nullable']
)
def upgrade():
data = get_data()
for table, column in data:
alter_column(table, column)
def contract_creation_exceptions():
"""Special migration for the blueprint to support Keystone V3.
We drop all tenant_id columns and create project_id columns instead.
"""
return {
sa.Column: ['.'.join([table, 'project_id']) for table in get_tables()],
sa.Index: get_tables()
}

View File

@ -1,32 +0,0 @@
# Copyright 2016 VMware, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""initial Newton no op contract script
Revision ID: 80c85b675b6e
Revises: start_neutron_taas
Create Date: 2016-05-06 04:58:04.510568
"""
from neutron.db.migration import cli
# revision identifiers, used by Alembic.
revision = '80c85b675b6e'
down_revision = 'start_neutron_taas'
branch_labels = (cli.CONTRACT_BRANCH,)
def upgrade():
pass

View File

@ -1,32 +0,0 @@
# Copyright 2016 VMware, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""initial Newton no op expand script
Revision ID: 04625466c6fa
Revises: start_neutron_taas
Create Date: 2016-05-06 05:17:30.172181
"""
from neutron.db.migration import cli
# revision identifiers, used by Alembic.
revision = '04625466c6fa'
down_revision = 'start_neutron_taas'
branch_labels = (cli.EXPAND_BRANCH,)
def upgrade():
pass

View File

@ -1,49 +0,0 @@
# Copyright 2016 FUJITSU LABORATORIES LTD.
#
# 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.
"""add status
Revision ID: fddbdec8711a
Revises: 04625466c6fa
Create Date: 2016-06-06 10:54:42.252898
"""
# revision identifiers, used by Alembic.
revision = 'fddbdec8711a'
down_revision = '04625466c6fa'
from alembic import op
from neutron.db import migration
from neutron_lib import constants
import sqlalchemy as sa
# milestone identifier, used by neutron-db-manage
neutron_milestone = [
migration.NEWTON,
migration.OCATA,
migration.PIKE,
migration.QUEENS,
migration.ROCKY,
]
def upgrade():
op.add_column('tap_services', sa.Column('status', sa.String(16),
server_default=constants.ACTIVE,
nullable=False))
op.add_column('tap_flows', sa.Column('status', sa.String(16),
server_default=constants.ACTIVE,
nullable=False))

View File

@ -1,56 +0,0 @@
# Copyright 2016-17
#
# 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.
"""Alter TapIdAssociations to support tap id reuse
Revision ID: bac61f603e39
Revises: 4086b3cffc01
Create Date: 2016-07-27 09:31:54.200165
"""
# revision identifiers, used by Alembic.
revision = 'bac61f603e39'
down_revision = '4086b3cffc01'
from alembic import op
from sqlalchemy.engine import reflection
import sqlalchemy as sa
from neutron.db import migration
# milestone identifier, used by neutron-db-manage
neutron_milestone = [migration.PIKE, migration.QUEENS, migration.ROCKY]
TABLE_NAME = 'tap_id_associations'
def upgrade():
inspector = reflection.Inspector.from_engine(op.get_bind())
fk_constraints = inspector.get_foreign_keys(TABLE_NAME)
for fk in fk_constraints:
op.drop_constraint(fk['name'], TABLE_NAME, type_='foreignkey')
op.create_foreign_key('fk_tap_id_assoc_tap_service', TABLE_NAME,
'tap_services', ['tap_service_id'], ['id'],
ondelete='SET NULL')
op.alter_column(TABLE_NAME, 'taas_id', autoincrement=False,
existing_type=sa.INTEGER, nullable=False)
op.alter_column(TABLE_NAME, 'tap_service_id',
existing_type=sa.String(36), nullable=True)
op.create_unique_constraint('unique_taas_id', TABLE_NAME,
['taas_id'])

View File

@ -1,32 +0,0 @@
# Copyright 2015 Midokura SARL
#
# 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.
"""start neutron-taas chain
Revision ID: start_neutron_taas
Revises: None
Create Date: 2015-11-11 02:36:00.209301
"""
# revision identifiers, used by Alembic.
revision = 'start_neutron_taas'
down_revision = None
from neutron_taas.db.migration import taas_init_ops
def upgrade():
taas_init_ops.upgrade()

View File

@ -1,54 +0,0 @@
# Copyright 2015 Ericsson AB
# Copyright (c) 2015 Gigamon
#
# 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.
#
# Initial schema operations for Tap-as-a-Service service plugin
from alembic import op
import sqlalchemy as sa
direction_types = sa.Enum('IN', 'OUT', 'BOTH', name='tapflows_direction')
def upgrade():
op.create_table(
'tap_services',
sa.Column('id', sa.String(length=36), primary_key=True,
nullable=False),
sa.Column('tenant_id', sa.String(length=255), nullable=True),
sa.Column('name', sa.String(length=255), nullable=True),
sa.Column('description', sa.String(length=1024), nullable=True),
sa.Column('port_id', sa.String(36), nullable=False),
sa.Column('network_id', sa.String(36), nullable=True))
op.create_table(
'tap_flows',
sa.Column('id', sa.String(length=36), primary_key=True,
nullable=False),
sa.Column('tenant_id', sa.String(length=255), nullable=True),
sa.Column('name', sa.String(length=255), nullable=True),
sa.Column('description', sa.String(length=1024), nullable=True),
sa.Column('tap_service_id', sa.String(length=36),
sa.ForeignKey("tap_services.id",
ondelete="CASCADE"), nullable=False),
sa.Column('source_port', sa.String(length=36), nullable=False),
sa.Column('direction', direction_types, nullable=False))
op.create_table(
'tap_id_associations',
sa.Column('tap_service_id', sa.String(length=36)),
sa.Column('taas_id', sa.INTEGER, primary_key=True, autoincrement=True))

View File

@ -1,287 +0,0 @@
# Copyright (C) 2015 Ericsson AB
# Copyright (c) 2015 Gigamon
#
# 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 sqlalchemy as sa
from sqlalchemy import orm
from sqlalchemy.orm import exc
from neutron_lib import constants
from neutron_lib.db import model_base
from neutron_lib.db import model_query
from neutron_lib.db import utils as db_utils
from neutron_lib.plugins import directory
from neutron_taas.extensions import taas
from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import uuidutils
LOG = logging.getLogger(__name__)
class TapService(model_base.BASEV2, model_base.HasId,
model_base.HasProjectNoIndex):
# Represents a V2 TapService Object
__tablename__ = 'tap_services'
name = sa.Column(sa.String(255), nullable=True)
description = sa.Column(sa.String(1024), nullable=True)
port_id = sa.Column(sa.String(36), nullable=False)
status = sa.Column(sa.String(16), nullable=False,
server_default=constants.ACTIVE)
class TapFlow(model_base.BASEV2, model_base.HasId,
model_base.HasProjectNoIndex):
# Represents a V2 TapFlow Object
__tablename__ = 'tap_flows'
name = sa.Column(sa.String(255), nullable=True)
description = sa.Column(sa.String(1024), nullable=True)
tap_service_id = sa.Column(sa.String(36),
sa.ForeignKey("tap_services.id",
ondelete="CASCADE"),
nullable=False)
source_port = sa.Column(sa.String(36), nullable=False)
direction = sa.Column(sa.Enum('IN', 'OUT', 'BOTH',
name='tapflows_direction'),
nullable=False)
status = sa.Column(sa.String(16), nullable=False,
server_default=constants.ACTIVE)
class TapIdAssociation(model_base.BASEV2):
# Internal mapping between a TAP Service and
# id to be used by the Agents
__tablename__ = 'tap_id_associations'
tap_service_id = sa.Column(sa.String(36),
sa.ForeignKey("tap_services.id",
ondelete='SET NULL'),
nullable=True)
taas_id = sa.Column(sa.Integer, primary_key=True, unique=True)
tap_service = orm.relationship(
TapService,
backref=orm.backref("tap_service_id",
lazy="joined"),
primaryjoin='TapService.id==TapIdAssociation.tap_service_id')
class Taas_db_Mixin(taas.TaasPluginBase):
def _core_plugin(self):
return directory.get_plugin()
def _get_tap_service(self, context, id):
try:
return model_query.get_by_id(context, TapService, id)
except exc.NoResultFound:
raise taas.TapServiceNotFound(tap_id=id)
def _get_tap_id_association(self, context, tap_service_id):
try:
query = model_query.query_with_hooks(context, TapIdAssociation)
return query.filter(TapIdAssociation.tap_service_id ==
tap_service_id).one()
except exc.NoResultFound:
raise taas.TapServiceNotFound(tap_id=tap_service_id)
def _get_tap_flow(self, context, id):
try:
return model_query.get_by_id(context, TapFlow, id)
except Exception:
raise taas.TapFlowNotFound(flow_id=id)
def _make_tap_service_dict(self, tap_service, fields=None):
res = {'id': tap_service['id'],
'tenant_id': tap_service['tenant_id'],
'name': tap_service['name'],
'description': tap_service['description'],
'port_id': tap_service['port_id'],
'status': tap_service['status']}
return db_utils.resource_fields(res, fields)
def _make_tap_id_association_dict(self, tap_id_association):
res = {'tap_service_id': tap_id_association['tap_service_id'],
'taas_id': tap_id_association['taas_id']}
return res
def _make_tap_flow_dict(self, tap_flow, fields=None):
res = {'id': tap_flow['id'],
'tenant_id': tap_flow['tenant_id'],
'tap_service_id': tap_flow['tap_service_id'],
'name': tap_flow['name'],
'description': tap_flow['description'],
'source_port': tap_flow['source_port'],
'direction': tap_flow['direction'],
'status': tap_flow['status']}
return db_utils.resource_fields(res, fields)
def create_tap_service(self, context, tap_service):
LOG.debug("create_tap_service() called")
t_s = tap_service['tap_service']
tenant_id = t_s['tenant_id']
with context.session.begin(subtransactions=True):
tap_service_db = TapService(
id=uuidutils.generate_uuid(),
tenant_id=tenant_id,
name=t_s['name'],
description=t_s['description'],
port_id=t_s['port_id'],
status=constants.ACTIVE,
)
context.session.add(tap_service_db)
return self._make_tap_service_dict(tap_service_db)
def _rebuild_taas_id_allocation_range(self, context):
query = context.session.query(
TapIdAssociation).all()
allocate_taas_id_list = [_q.taas_id for _q in query]
first_taas_id = cfg.CONF.taas.vlan_range_start
# Exclude range end
last_taas_id = cfg.CONF.taas.vlan_range_end
all_taas_id_set = set(range(first_taas_id, last_taas_id))
vaild_taas_id_set = all_taas_id_set - set(allocate_taas_id_list)
for _id in vaild_taas_id_set:
# new taas id
context.session.add(TapIdAssociation(
taas_id=_id))
def _allocate_taas_id_with_tap_service_id(self, context, tap_service_id):
query = context.session.query(TapIdAssociation).filter_by(
tap_service_id=None).first()
if not query:
self._rebuild_taas_id_allocation_range(context)
# try again
query = context.session.query(TapIdAssociation).filter_by(
tap_service_id=None).first()
if query:
query.update({"tap_service_id": tap_service_id})
return query
# not found
raise taas.TapServiceLimitReached()
def create_tap_id_association(self, context, tap_service_id):
LOG.debug("create_tap_id_association() called")
# create the TapIdAssociation object
with context.session.begin(subtransactions=True):
# allocate Taas id.
# if conflict happened, it will raise db.DBDuplicateEntry.
# this will be retry request again in neutron controller framework.
# so we just make sure TapIdAssociation field taas_id is unique
tap_id_association_db = self._allocate_taas_id_with_tap_service_id(
context, tap_service_id)
return self._make_tap_id_association_dict(tap_id_association_db)
def create_tap_flow(self, context, tap_flow):
LOG.debug("create_tap_flow() called")
t_f = tap_flow['tap_flow']
tenant_id = t_f['tenant_id']
# TODO(Vinay): Check for the tenant_id validation
# TODO(Vinay): Check for the source port validation
with context.session.begin(subtransactions=True):
tap_flow_db = TapFlow(
id=uuidutils.generate_uuid(),
tenant_id=tenant_id,
name=t_f['name'],
description=t_f['description'],
tap_service_id=t_f['tap_service_id'],
source_port=t_f['source_port'],
direction=t_f['direction'],
status=constants.ACTIVE,
)
context.session.add(tap_flow_db)
return self._make_tap_flow_dict(tap_flow_db)
def delete_tap_service(self, context, id):
LOG.debug("delete_tap_service() called")
count = context.session.query(TapService).filter_by(id=id).delete()
if not count:
raise taas.TapServiceNotFound(tap_id=id)
def delete_tap_flow(self, context, id):
LOG.debug("delete_tap_flow() called")
count = context.session.query(TapFlow).filter_by(id=id).delete()
if not count:
raise taas.TapFlowNotFound(flow_id=id)
def get_tap_service(self, context, id, fields=None):
LOG.debug("get_tap_service() called")
t_s = self._get_tap_service(context, id)
return self._make_tap_service_dict(t_s, fields)
def get_tap_id_association(self, context, tap_service_id):
LOG.debug("get_tap_id_association() called")
t_a = self._get_tap_id_association(context, tap_service_id)
return self._make_tap_id_association_dict(t_a)
def get_tap_flow(self, context, id, fields=None):
LOG.debug("get_tap_flow() called")
t_f = self._get_tap_flow(context, id)
return self._make_tap_flow_dict(t_f, fields)
def get_tap_services(self, context, filters=None, fields=None,
sorts=None, limit=None, marker=None,
page_reverse=False):
LOG.debug("get_tap_services() called")
return model_query.get_collection(context, TapService,
self._make_tap_service_dict,
filters=filters, fields=fields)
def get_tap_flows(self, context, filters=None, fields=None,
sorts=None, limit=None, marker=None,
page_reverse=False):
LOG.debug("get_tap_flows() called")
return model_query.get_collection(context, TapFlow,
self._make_tap_flow_dict,
filters=filters, fields=fields)
def _get_port_details(self, context, port_id):
with context.session.begin(subtransactions=True):
port = self._core_plugin().get_port(context, port_id)
return port
def update_tap_service(self, context, id, tap_service):
LOG.debug("update_tap_service() called")
t_s = tap_service['tap_service']
with context.session.begin(subtransactions=True):
tap_service_db = self._get_tap_service(context, id)
tap_service_db.update(t_s)
return self._make_tap_service_dict(tap_service_db)
def update_tap_flow(self, context, id, tap_flow):
LOG.debug("update_tap_flow() called")
t_f = tap_flow['tap_flow']
with context.session.begin(subtransactions=True):
tap_flow_db = self._get_tap_flow(context, id)
tap_flow_db.update(t_f)
return self._make_tap_flow_dict(tap_flow_db)

View File

@ -1,260 +0,0 @@
# Copyright (C) 2015 Ericsson AB
# Copyright (c) 2015 Gigamon
#
# 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 abc
from neutron_lib.api import extensions
from neutron_lib import exceptions as qexception
from neutron_lib.services import base as service_base
from neutron.api.v2 import resource_helper
from neutron_taas._i18n import _
from neutron_taas.common import constants
from oslo_config import cfg
import six
# TaaS exception handling classes
class TapServiceNotFound(qexception.NotFound):
message = _("Tap Service %(tap_id)s does not exist")
class TapFlowNotFound(qexception.NotFound):
message = _("Tap Flow %(flow_id)s does not exist")
class InvalidDestinationPort(qexception.NotFound):
message = _("Destination Port %(port)s does not exist")
class InvalidSourcePort(qexception.NotFound):
message = _("Source Port %(port)s does not exist")
class PortDoesNotBelongToTenant(qexception.NotAuthorized):
message = _("The specified port does not belong to the tenant")
class TapServiceNotBelongToTenant(qexception.NotAuthorized):
message = _("Specified Tap Service does not belong to the tenant")
class TapServiceLimitReached(qexception.OverQuota):
message = _("Reached the maximum quota for Tap Services")
direction_enum = ['IN', 'OUT', 'BOTH']
'''
Resource Attribute Map:
Note:
'tap_services' data model refers to the Tap Service created.
port_id specifies destination port to which the mirrored data is sent.
'''
RESOURCE_ATTRIBUTE_MAP = {
'tap_services': {
'id': {'allow_post': False, 'allow_put': False,
'validate': {'type:uuid': None}, 'is_visible': True,
'primary_key': True},
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True, 'is_visible': True},
'name': {'allow_post': True, 'allow_put': True,
'validate': {'type:string': None},
'is_visible': True, 'default': ''},
'description': {'allow_post': True, 'allow_put': True,
'validate': {'type:string': None},
'is_visible': True, 'default': ''},
'port_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:uuid': None},
'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True}
},
'tap_flows': {
'id': {'allow_post': False, 'allow_put': False,
'validate': {'type:uuid': None}, 'is_visible': True,
'primary_key': True},
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True, 'is_visible': True},
'name': {'allow_post': True, 'allow_put': True,
'validate': {'type:string': None},
'is_visible': True, 'default': ''},
'description': {'allow_post': True, 'allow_put': True,
'validate': {'type:string': None},
'is_visible': True, 'default': ''},
'tap_service_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:uuid': None},
'required_by_policy': True, 'is_visible': True},
'source_port': {'allow_post': True, 'allow_put': False,
'validate': {'type:uuid': None},
'required_by_policy': True, 'is_visible': True},
'direction': {'allow_post': True, 'allow_put': False,
'validate': {'type:values': direction_enum},
'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True}
}
}
taas_quota_opts = [
cfg.IntOpt('quota_tap_service',
default=1,
help=_('Number of Tap Service instances allowed per tenant')),
cfg.IntOpt('quota_tap_flow',
default=10,
help=_('Number of Tap flows allowed per tenant'))
]
cfg.CONF.register_opts(taas_quota_opts, 'QUOTAS')
TaasOpts = [
cfg.StrOpt(
'driver',
default='',
help=_("Name of the TaaS Driver")),
cfg.BoolOpt(
'enabled',
default=False,
help=_("Enable TaaS")),
cfg.IntOpt(
'vlan_range_start',
default=3900,
help=_("Starting range of TAAS VLAN IDs")),
cfg.IntOpt(
'vlan_range_end',
default=4000,
help=_("End range of TAAS VLAN IDs")),
]
cfg.CONF.register_opts(TaasOpts, 'taas')
class Taas(extensions.ExtensionDescriptor):
@classmethod
def get_name(cls):
return "Neutron Tap as a Service"
@classmethod
def get_alias(cls):
return "taas"
@classmethod
def get_description(cls):
return "Neutron Tap as a Service Extension."
@classmethod
def get_updated(cls):
return "2015-01-14T10:00:00-00:00"
@classmethod
def get_plugin_interface(cls):
return TaasPluginBase
@classmethod
def get_resources(cls):
"""Returns Ext Resources."""
plural_mappings = resource_helper.build_plural_mappings(
{}, RESOURCE_ATTRIBUTE_MAP)
return resource_helper.build_resource_info(plural_mappings,
RESOURCE_ATTRIBUTE_MAP,
constants.TAAS,
translate_name=False,
allow_bulk=True)
def update_attributes_map(self, attributes):
super(Taas, self).update_attributes_map(
attributes, extension_attrs_map=RESOURCE_ATTRIBUTE_MAP)
def get_extended_resources(self, version):
if version == "2.0":
return RESOURCE_ATTRIBUTE_MAP
else:
return {}
@six.add_metaclass(abc.ABCMeta)
class TaasPluginBase(service_base.ServicePluginBase):
def get_plugin_description(self):
return "Tap Service Plugin"
@classmethod
def get_plugin_type(cls):
return constants.TAAS
@abc.abstractmethod
def create_tap_service(self, context, tap_service):
"""Create a Tap Service."""
pass
@abc.abstractmethod
def delete_tap_service(self, context, id):
"""Delete a Tap Service."""
pass
@abc.abstractmethod
def get_tap_service(self, context, id, fields=None):
"""Get a Tap Service."""
pass
@abc.abstractmethod
def get_tap_services(self, context, filters=None, fields=None,
sorts=None, limit=None, marker=None,
page_reverse=False):
"""List all Tap Services."""
pass
@abc.abstractmethod
def update_tap_service(self, context, id, tap_service):
"""Update a Tap Service."""
pass
@abc.abstractmethod
def create_tap_flow(self, context, tap_flow):
"""Create a Tap Flow."""
pass
@abc.abstractmethod
def get_tap_flow(self, context, id, fields=None):
"""Get a Tap Flow."""
pass
@abc.abstractmethod
def delete_tap_flow(self, context, id):
"""Delete a Tap Flow."""
pass
@abc.abstractmethod
def get_tap_flows(self, context, filters=None, fields=None,
sorts=None, limit=None, marker=None,
page_reverse=False):
"""List all Tap Flows."""
pass
@abc.abstractmethod
def update_tap_flow(self, context, id, tap_flow):
"""Update a Tap Flow."""
pass

View File

@ -1,91 +0,0 @@
# Copyright 2017 FUJITSU LABORATORIES LTD.
# Copyright 2016 NEC Technologies India Pvt. Ltd.
#
# 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 abc
import six
from neutron_lib.agent import l2_extension
from neutron_taas.services.taas.agents.ovs import taas_ovs_agent
from oslo_config import cfg
from oslo_log import log as logging
LOG = logging.getLogger(__name__)
OPTS = [
cfg.IntOpt(
'taas_agent_periodic_interval',
default=5,
help=_('Seconds between periodic task runs')
)
]
cfg.CONF.register_opts(OPTS)
@six.add_metaclass(abc.ABCMeta)
class TaasAgentDriver(object):
"""Defines stable abstract interface for TaaS Agent Driver."""
@abc.abstractmethod
def initialize(self):
"""Perform Taas agent driver initialization."""
def consume_api(self, agent_api):
"""Consume the AgentAPI instance from the TaasAgentExtension class
:param agent_api: An instance of an agent specific API
"""
@abc.abstractmethod
def create_tap_service(self, tap_service):
"""Create a Tap Service request in driver."""
@abc.abstractmethod
def create_tap_flow(self, tap_flow):
"""Create a tap flow request in driver."""
@abc.abstractmethod
def delete_tap_service(self, tap_service):
"""delete a Tap Service request in driver."""
@abc.abstractmethod
def delete_tap_flow(self, tap_flow):
"""Delete a tap flow request in driver."""
class TaasAgentExtension(l2_extension.L2AgentExtension):
def initialize(self, connection, driver_type):
"""Initialize agent extension."""
self.taas_agent = taas_ovs_agent.TaasOvsAgentRpcCallback(
cfg.CONF, driver_type)
self.taas_agent.consume_api(self.agent_api)
self.taas_agent.initialize()
def consume_api(self, agent_api):
"""Receive neutron agent API object
Allows an extension to gain access to resources internal to the
neutron agent and otherwise unavailable to the extension.
"""
self.agent_api = agent_api
def handle_port(self, context, port):
pass
def delete_port(self, context, port):
pass

View File

@ -1,144 +0,0 @@
# Copyright (C) 2015 Ericsson AB
# Copyright (c) 2015 Gigamon
#
# 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 import manager
from neutron_taas.common import topics
from neutron_taas.services.taas.agents import taas_agent_api as api
from neutron_lib import rpc as n_rpc
from oslo_config import cfg
from oslo_log import log as logging
from oslo_service import service
LOG = logging.getLogger(__name__)
class TaasOvsPluginApi(api.TaasPluginApiMixin):
# Currently there are not any APIs from the the agent towards plugin
def __init__(self, topic, host):
super(TaasOvsPluginApi, self).__init__(topic, host)
return
class TaasOvsAgentRpcCallback(api.TaasAgentRpcCallbackMixin):
def __init__(self, conf, driver_type):
LOG.debug("TaaS OVS Agent initialize called")
self.conf = conf
self.driver_type = driver_type
super(TaasOvsAgentRpcCallback, self).__init__()
def initialize(self):
self.taas_driver = manager.NeutronManager.load_class_for_provider(
'neutron_taas.taas.agent_drivers', self.driver_type)()
self.taas_driver.consume_api(self.agent_api)
self.taas_driver.initialize()
self._taas_rpc_setup()
TaasOvsAgentService(self).start()
def consume_api(self, agent_api):
self.agent_api = agent_api
def _invoke_driver_for_plugin_api(self, context, args, func_name):
LOG.debug("Invoking Driver for %(func_name)s from agent",
{'func_name': func_name})
try:
self.taas_driver.__getattribute__(func_name)(args)
except Exception:
LOG.debug("Failed to invoke the driver")
return
def create_tap_service(self, context, tap_service, host):
"""Handle Rpc from plugin to create a tap_service."""
if host != self.conf.host:
return
LOG.debug("In RPC Call for Create Tap Service: MSG=%s" % tap_service)
return self._invoke_driver_for_plugin_api(
context,
tap_service,
'create_tap_service')
def create_tap_flow(self, context, tap_flow_msg, host):
if host != self.conf.host:
return
LOG.debug("In RPC Call for Create Tap Flow: MSG=%s" % tap_flow_msg)
return self._invoke_driver_for_plugin_api(
context,
tap_flow_msg,
'create_tap_flow')
def delete_tap_service(self, context, tap_service, host):
#
# Cleanup operations must be performed by all hosts
# where the source and/or destination ports associated
# with this tap service were residing.
#
LOG.debug("In RPC Call for Delete Tap Service: MSG=%s" % tap_service)
return self._invoke_driver_for_plugin_api(
context,
tap_service,
'delete_tap_service')
def delete_tap_flow(self, context, tap_flow_msg, host):
if host != self.conf.host:
return
LOG.debug("In RPC Call for Delete Tap Flow: MSG=%s" % tap_flow_msg)
return self._invoke_driver_for_plugin_api(
context,
tap_flow_msg,
'delete_tap_flow')
def _taas_rpc_setup(self):
# setup RPC to msg taas plugin
self.taas_plugin_rpc = TaasOvsPluginApi(
topics.TAAS_PLUGIN, self.conf.host)
endpoints = [self]
conn = n_rpc.Connection()
conn.create_consumer(topics.TAAS_AGENT, endpoints, fanout=False)
conn.consume_in_threads()
def periodic_tasks(self):
#
# Regenerate the flow in br-tun's TAAS_SEND_FLOOD table
# to ensure all existing tunnel ports are included.
#
self.taas_driver.update_tunnel_flood_flow()
class TaasOvsAgentService(service.Service):
def __init__(self, driver):
super(TaasOvsAgentService, self).__init__()
self.driver = driver
def start(self):
super(TaasOvsAgentService, self).start()
self.tg.add_timer(
int(cfg.CONF.taas_agent_periodic_interval),
self.driver.periodic_tasks,
None
)

View File

@ -1,75 +0,0 @@
# Copyright (C) 2015 Ericsson AB
# Copyright (c) 2015 Gigamon
#
# 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_lib import rpc as n_rpc
from neutron_taas._i18n import _
from oslo_config import cfg
import oslo_messaging as messaging
TaasOpts = [
cfg.StrOpt(
'driver',
default='',
help=_("Name of the TaaS Driver")),
cfg.BoolOpt(
'enabled',
default=False,
help=_("Enable TaaS")),
]
cfg.CONF.register_opts(TaasOpts, 'taas')
class TaasPluginApiMixin(object):
# Currently there are no Calls the Agent makes towards the Plugin.
def __init__(self, topic, host):
self.host = host
target = messaging.Target(topic=topic, version='1.0')
self.client = n_rpc.get_client(target)
super(TaasPluginApiMixin, self).__init__()
return
class TaasAgentRpcCallbackMixin(object):
"""Mixin for Taas agent Implementations."""
def __init__(self):
super(TaasAgentRpcCallbackMixin, self).__init__()
def consume_api(self, agent_api):
"""Receive neutron agent API object
Allows an extension to gain access to resources internal to the
neutron agent and otherwise unavailable to the extension.
"""
self.agent_api = agent_api
def create_tap_service(self, context, tap_service, host):
"""Handle RPC cast from plugin to create a tap service."""
pass
def delete_tap_service(self, context, tap_service, host):
"""Handle RPC cast from plugin to delete a tap service."""
pass
def create_tap_flow(self, context, tap_flow_msg, host):
"""Handle RPC cast from plugin to create a tap flow"""
pass
def delete_tap_flow(self, context, tap_flow_msg, host):
"""Handle RPC cast from plugin to delete a tap flow"""
pass

View File

@ -1,28 +0,0 @@
# Copyright (C) 2015 Ericsson AB
# Copyright (c) 2015 Gigamon
#
# 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.
# OVS tables used by TaaS in br-tap
TAAS_RECV_LOC = 1
TAAS_RECV_REM = 2
# OVS tables used by TaaS in br-tun
TAAS_SEND_UCAST = 30
TAAS_SEND_FLOOD = 31
TAAS_CLASSIFY = 35
TAAS_DST_CHECK = 36
TAAS_SRC_CHECK = 37
TAAS_DST_RESPOND = 38
TAAS_SRC_RESPOND = 39

View File

@ -1,507 +0,0 @@
# Copyright (C) 2015 Ericsson AB
# Copyright (c) 2015 Gigamon
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from neutron.agent.common import ovs_lib
from neutron.agent.linux import utils
from neutron.conf.agent import common
# from neutron.plugins.openvswitch.common import constants as ovs_consts
from neutron.plugins.ml2.drivers.openvswitch.agent.common import constants \
as ovs_consts
from neutron_taas.services.taas.agents.extensions import taas as taas_base
import neutron_taas.services.taas.drivers.linux.ovs_constants \
as taas_ovs_consts
import neutron_taas.services.taas.drivers.linux.ovs_utils as taas_ovs_utils
from oslo_config import cfg
from oslo_log import log as logging
LOG = logging.getLogger(__name__)
TaaS_DRIVER_NAME = 'Taas OVS driver'
class OVSBridge_tap_extension(ovs_lib.OVSBridge):
def __init__(self, br_name, root_helper):
super(OVSBridge_tap_extension, self).__init__(br_name)
class OvsTaasDriver(taas_base.TaasAgentDriver):
def __init__(self):
super(OvsTaasDriver, self).__init__()
LOG.debug("Initializing Taas OVS Driver")
self.agent_api = None
self.root_helper = common.get_root_helper(cfg.CONF)
def initialize(self):
self.int_br = self.agent_api.request_int_br()
self.tun_br = self.agent_api.request_tun_br()
self.tap_br = OVSBridge_tap_extension('br-tap', self.root_helper)
# Prepare OVS bridges for TaaS
self.setup_ovs_bridges()
# Setup key-value manager for ingress BCMC flows
self.bcmc_kvm = taas_ovs_utils.key_value_mgr(4096)
def setup_ovs_bridges(self):
#
# br-int : Integration Bridge
# br-tap : Tap Bridge
# br-tun : Tunnel Bridge
#
# Create br-tap
self.tap_br.create()
# Connect br-tap to br-int and br-tun
self.int_br.add_patch_port('patch-int-tap', 'patch-tap-int')
self.tap_br.add_patch_port('patch-tap-int', 'patch-int-tap')
self.tun_br.add_patch_port('patch-tun-tap', 'patch-tap-tun')
self.tap_br.add_patch_port('patch-tap-tun', 'patch-tun-tap')
# Get patch port IDs
patch_tap_int_id = self.tap_br.get_port_ofport('patch-tap-int')
patch_tap_tun_id = self.tap_br.get_port_ofport('patch-tap-tun')
patch_tun_tap_id = self.tun_br.get_port_ofport('patch-tun-tap')
# Purge all existing Taas flows from br-tap and br-tun
self.tap_br.delete_flows(table=0)
self.tap_br.delete_flows(table=taas_ovs_consts.TAAS_RECV_LOC)
self.tap_br.delete_flows(table=taas_ovs_consts.TAAS_RECV_REM)
self.tun_br.delete_flows(table=0,
in_port=patch_tun_tap_id)
self.tun_br.delete_flows(table=taas_ovs_consts.TAAS_SEND_UCAST)
self.tun_br.delete_flows(table=taas_ovs_consts.TAAS_SEND_FLOOD)
self.tun_br.delete_flows(table=taas_ovs_consts.TAAS_CLASSIFY)
self.tun_br.delete_flows(table=taas_ovs_consts.TAAS_DST_CHECK)
self.tun_br.delete_flows(table=taas_ovs_consts.TAAS_SRC_CHECK)
self.tun_br.delete_flows(table=taas_ovs_consts.TAAS_DST_RESPOND)
self.tun_br.delete_flows(table=taas_ovs_consts.TAAS_SRC_RESPOND)
#
# Configure standard TaaS flows in br-tap
#
self.tap_br.add_flow(table=0,
priority=1,
in_port=patch_tap_int_id,
actions="resubmit(,%s)" %
taas_ovs_consts.TAAS_RECV_LOC)
self.tap_br.add_flow(table=0,
priority=1,
in_port=patch_tap_tun_id,
actions="resubmit(,%s)" %
taas_ovs_consts.TAAS_RECV_REM)
self.tap_br.add_flow(table=0,
priority=0,
actions="drop")
self.tap_br.add_flow(table=taas_ovs_consts.TAAS_RECV_LOC,
priority=0,
actions="output:%s" % str(patch_tap_tun_id))
self.tap_br.add_flow(table=taas_ovs_consts.TAAS_RECV_REM,
priority=0,
actions="drop")
#
# Configure standard Taas flows in br-tun
#
self.tun_br.add_flow(table=0,
priority=1,
in_port=patch_tun_tap_id,
actions="resubmit(,%s)" %
taas_ovs_consts.TAAS_SEND_UCAST)
self.tun_br.add_flow(table=taas_ovs_consts.TAAS_SEND_UCAST,
priority=0,
actions="resubmit(,%s)" %
taas_ovs_consts.TAAS_SEND_FLOOD)
flow_action = self._create_tunnel_flood_flow_action()
if flow_action != "":
self.tun_br.add_flow(table=taas_ovs_consts.TAAS_SEND_FLOOD,
priority=0,
actions=flow_action)
self.tun_br.add_flow(table=taas_ovs_consts.TAAS_CLASSIFY,
priority=2,
reg0=0,
actions="resubmit(,%s)" %
taas_ovs_consts.TAAS_DST_CHECK)
self.tun_br.add_flow(table=taas_ovs_consts.TAAS_CLASSIFY,
priority=1,
reg0=1,
actions="resubmit(,%s)" %
taas_ovs_consts.TAAS_DST_CHECK)
self.tun_br.add_flow(table=taas_ovs_consts.TAAS_CLASSIFY,
priority=1,
reg0=2,
actions="resubmit(,%s)" %
taas_ovs_consts.TAAS_SRC_CHECK)
self.tun_br.add_flow(table=taas_ovs_consts.TAAS_DST_CHECK,
priority=0,
actions="drop")
self.tun_br.add_flow(table=taas_ovs_consts.TAAS_SRC_CHECK,
priority=0,
actions="drop")
self.tun_br.add_flow(table=taas_ovs_consts.TAAS_DST_RESPOND,
priority=2,
reg0=0,
actions="output:%s" % str(patch_tun_tap_id))
self.tun_br.add_flow(table=taas_ovs_consts.TAAS_DST_RESPOND,
priority=1,
reg0=1,
actions=(
"output:%s,"
"move:NXM_OF_VLAN_TCI[0..11]->NXM_NX_TUN_ID"
"[0..11],mod_vlan_vid:2,output:in_port" %
str(patch_tun_tap_id)))
self.tun_br.add_flow(table=taas_ovs_consts.TAAS_SRC_RESPOND,
priority=1,
actions=(
"learn(table=%s,hard_timeout=60,"
"priority=1,NXM_OF_VLAN_TCI[0..11],"
"load:NXM_OF_VLAN_TCI[0..11]->NXM_NX_TUN_ID"
"[0..11],load:0->NXM_OF_VLAN_TCI[0..11],"
"output:NXM_OF_IN_PORT[])" %
taas_ovs_consts.TAAS_SEND_UCAST))
return
def consume_api(self, agent_api):
self.agent_api = agent_api
def create_tap_service(self, tap_service):
taas_id = tap_service['taas_id']
port = tap_service['port']
# Get OVS port id for tap service port
ovs_port = self.int_br.get_vif_port_by_id(port['id'])
ovs_port_id = ovs_port.ofport
# Get VLAN id for tap service port
port_dict = self.int_br.get_port_tag_dict()
port_vlan_id = port_dict[ovs_port.port_name]
# Get patch port IDs
patch_int_tap_id = self.int_br.get_port_ofport('patch-int-tap')
patch_tap_int_id = self.tap_br.get_port_ofport('patch-tap-int')
# Add flow(s) in br-int
self.int_br.add_flow(table=0,
priority=25,
in_port=patch_int_tap_id,
dl_vlan=taas_id,
actions="mod_vlan_vid:%s,output:%s" %
(str(port_vlan_id), str(ovs_port_id)))
# Add flow(s) in br-tap
self.tap_br.add_flow(table=taas_ovs_consts.TAAS_RECV_LOC,
priority=1,
dl_vlan=taas_id,
actions="output:in_port")
self.tap_br.add_flow(table=taas_ovs_consts.TAAS_RECV_REM,
priority=1,
dl_vlan=taas_id,
actions="output:%s" % str(patch_tap_int_id))
# Add flow(s) in br-tun
for tunnel_type in ovs_consts.TUNNEL_NETWORK_TYPES:
self.tun_br.add_flow(table=ovs_consts.TUN_TABLE[tunnel_type],
priority=1,
tun_id=taas_id,
actions=(
"move:NXM_OF_VLAN_TCI[0..11]->"
"NXM_NX_REG0[0..11],move:NXM_NX_TUN_ID"
"[0..11]->NXM_OF_VLAN_TCI[0..11],"
"resubmit(,%s)" %
taas_ovs_consts.TAAS_CLASSIFY))
self.tun_br.add_flow(table=taas_ovs_consts.TAAS_DST_CHECK,
priority=1,
tun_id=taas_id,
actions="resubmit(,%s)" %
taas_ovs_consts.TAAS_DST_RESPOND)
#
# Disable mac-address learning in the Linux bridge to which
# the OVS port is attached (via the veth pair). This will
# effectively turn the bridge into a hub, ensuring that all
# incoming mirrored traffic reaches the tap interface (used
# for attaching a VM to the bridge) irrespective of the
# destination mac addresses in mirrored packets.
#
ovs_port_name = ovs_port.port_name
linux_br_name = ovs_port_name.replace('qvo', 'qbr')
utils.execute(['brctl', 'setageing', linux_br_name, 0],
run_as_root=True)
return
def delete_tap_service(self, tap_service):
taas_id = tap_service['taas_id']
# Get patch port ID
patch_int_tap_id = self.int_br.get_port_ofport('patch-int-tap')
# Delete flow(s) from br-int
self.int_br.delete_flows(table=0,
in_port=patch_int_tap_id,
dl_vlan=taas_id)
# Delete flow(s) from br-tap
self.tap_br.delete_flows(table=taas_ovs_consts.TAAS_RECV_LOC,
dl_vlan=taas_id)
self.tap_br.delete_flows(table=taas_ovs_consts.TAAS_RECV_REM,
dl_vlan=taas_id)
# Delete flow(s) from br-tun
for tunnel_type in ovs_consts.TUNNEL_NETWORK_TYPES:
self.tun_br.delete_flows(table=ovs_consts.TUN_TABLE[tunnel_type],
tun_id=taas_id)
self.tun_br.delete_flows(table=taas_ovs_consts.TAAS_DST_CHECK,
tun_id=taas_id)
self.tun_br.delete_flows(table=taas_ovs_consts.TAAS_SRC_CHECK,
tun_id=taas_id)
return
def create_tap_flow(self, tap_flow):
taas_id = tap_flow['taas_id']
port = tap_flow['port']
direction = tap_flow['tap_flow']['direction']
# Get OVS port id for tap flow port
ovs_port = self.int_br.get_vif_port_by_id(port['id'])
ovs_port_id = ovs_port.ofport
# Get patch port ID
patch_int_tap_id = self.int_br.get_port_ofport('patch-int-tap')
# Add flow(s) in br-int
if direction == 'OUT' or direction == 'BOTH':
self.int_br.add_flow(table=0,
priority=20,
in_port=ovs_port_id,
actions="normal,mod_vlan_vid:%s,output:%s" %
(str(taas_id), str(patch_int_tap_id)))
if direction == 'IN' or direction == 'BOTH':
port_mac = tap_flow['port_mac']
#
# Note: The ingress side flow (for unicast traffic) should
# include a check for the 'VLAN id of the Neutron
# network the port belongs to' + 'MAC address of the
# port', to comply with the requirement that port MAC
# addresses are unique only within a Neutron network.
# Unfortunately, at the moment there is no clean way
# to implement such a check, given OVS's handling of
# VLAN tags and Neutron's use of the NORMAL action in
# br-int.
#
# We are therefore temporarily disabling the VLAN id
# check until a mechanism is available to implement
# it correctly. The {broad,multi}cast flow, which is
# also dependent on the VLAN id, has been disabled
# for the same reason.
#
# Get VLAN id for tap flow port
# port_dict = self.int_br.get_port_tag_dict()
# port_vlan_id = port_dict[ovs_port.port_name]
self.int_br.add_flow(table=0,
priority=20,
# dl_vlan=port_vlan_id,
dl_dst=port_mac,
actions="normal,mod_vlan_vid:%s,output:%s" %
(str(taas_id), str(patch_int_tap_id)))
# self._add_update_ingress_bcmc_flow(port_vlan_id,
# taas_id,
# patch_int_tap_id)
# Add flow(s) in br-tun
for tunnel_type in ovs_consts.TUNNEL_NETWORK_TYPES:
self.tun_br.add_flow(table=ovs_consts.TUN_TABLE[tunnel_type],
priority=1,
tun_id=taas_id,
actions=(
"move:NXM_OF_VLAN_TCI[0..11]->"
"NXM_NX_REG0[0..11],move:NXM_NX_TUN_ID"
"[0..11]->NXM_OF_VLAN_TCI[0..11],"
"resubmit(,%s)" %
taas_ovs_consts.TAAS_CLASSIFY))
self.tun_br.add_flow(table=taas_ovs_consts.TAAS_SRC_CHECK,
priority=1,
tun_id=taas_id,
actions="resubmit(,%s)" %
taas_ovs_consts.TAAS_SRC_RESPOND)
return
def delete_tap_flow(self, tap_flow):
port = tap_flow['port']
direction = tap_flow['tap_flow']['direction']
# Get OVS port id for tap flow port
ovs_port = self.int_br.get_vif_port_by_id(port['id'])
ovs_port_id = ovs_port.ofport
# Delete flow(s) from br-int
if direction == 'OUT' or direction == 'BOTH':
self.int_br.delete_flows(table=0,
in_port=ovs_port_id)
if direction == 'IN' or direction == 'BOTH':
port_mac = tap_flow['port_mac']
#
# The VLAN id related checks have been temporarily disabled.
# Please see comment in create_tap_flow() for details.
#
# taas_id = tap_flow['taas_id']
# Get VLAN id for tap flow port
# port_dict = self.int_br.get_port_tag_dict()
# port_vlan_id = port_dict[ovs_port.port_name]
# Get patch port ID
# patch_int_tap_id = self.int_br.get_port_ofport('patch-int-tap')
self.int_br.delete_flows(table=0,
# dl_vlan=port_vlan_id,
dl_dst=port_mac)
# self._del_update_ingress_bcmc_flow(port_vlan_id,
# taas_id,
# patch_int_tap_id)
return
def update_tunnel_flood_flow(self):
flow_action = self._create_tunnel_flood_flow_action()
if flow_action != "":
self.tun_br.mod_flow(table=taas_ovs_consts.TAAS_SEND_FLOOD,
actions=flow_action)
def _create_tunnel_flood_flow_action(self):
args = ["ovs-vsctl", "list-ports", "br-tun"]
res = utils.execute(args, run_as_root=True)
port_name_list = res.splitlines()
flow_action = ("move:NXM_OF_VLAN_TCI[0..11]->NXM_NX_TUN_ID[0..11],"
"mod_vlan_vid:1")
tunnel_ports_exist = False
for port_name in port_name_list:
if (port_name != 'patch-int') and (port_name != 'patch-tun-tap'):
flow_action += (",output:%d" %
self.tun_br.get_port_ofport(port_name))
tunnel_ports_exist = True
if tunnel_ports_exist:
return flow_action
else:
return ""
def _create_ingress_bcmc_flow_action(self, taas_id_list, out_port_id):
flow_action = "normal"
for taas_id in taas_id_list:
flow_action += (",mod_vlan_vid:%d,output:%d" %
(taas_id, out_port_id))
return flow_action
#
# Adds or updates a special flow in br-int to mirror (duplicate and
# redirect to 'out_port_id') all ingress broadcast/multicast traffic,
# associated with a VLAN, to possibly multiple tap service instances.
#
def _add_update_ingress_bcmc_flow(self, vlan_id, taas_id, out_port_id):
# Add a tap service instance affiliation with VLAN
self.bcmc_kvm.affiliate(vlan_id, taas_id)
# Find all tap service instances affiliated with VLAN
taas_id_list = self.bcmc_kvm.list_affiliations(vlan_id)
#
# Add/update flow to mirror ingress BCMC traffic, associated
# with VLAN, to all affiliated tap-service instances.
#
flow_action = self._create_ingress_bcmc_flow_action(taas_id_list,
out_port_id)
self.int_br.add_flow(table=0,
priority=20,
dl_vlan=vlan_id,
dl_dst="01:00:00:00:00:00/01:00:00:00:00:00",
actions=flow_action)
return
#
# Removes or updates a special flow in br-int to mirror (duplicate
# and redirect to 'out_port_id') all ingress broadcast/multicast
# traffic, associated with a VLAN, to possibly multiple tap-service
# instances.
#
def _del_update_ingress_bcmc_flow(self, vlan_id, taas_id, out_port_id):
# Remove a tap-service instance affiliation with VLAN
self.bcmc_kvm.unaffiliate(vlan_id, taas_id)
# Find all tap-service instances affiliated with VLAN
taas_id_list = self.bcmc_kvm.list_affiliations(vlan_id)
#
# If there are tap service instances affiliated with VLAN, update
# the flow to mirror ingress BCMC traffic, associated with VLAN,
# to all of them. Otherwise, remove the flow.
#
if taas_id_list:
flow_action = self._create_ingress_bcmc_flow_action(taas_id_list,
out_port_id)
self.int_br.add_flow(table=0,
priority=20,
dl_vlan=vlan_id,
dl_dst="01:00:00:00:00:00/01:00:00:00:00:00",
actions=flow_action)
else:
self.int_br.delete_flows(table=0,
dl_vlan=vlan_id,
dl_dst=("01:00:00:00:00:00/"
"01:00:00:00:00:00"))
return

View File

@ -1,99 +0,0 @@
# Copyright (C) 2015 Ericsson AB
# Copyright (c) 2015 Gigamon
#
# 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 class implements a simple key-value manager that can support
# the following relationships.
#
# - Multiple values may be affiliated with a key.
# - A value may be affiliated with multiple keys.
# - A value may be affiliated with a key multiple times.
#
class key_value_mgr(object):
#
# Initializes internal state for specified # keys
#
def __init__(self, nr_keys):
self.key_list = []
for i in range(nr_keys):
self.key_list.append([])
return
#
# Returns specified key-value affilation, if it exists.
#
def _find_affiliation(self, key, value):
aff_list = self.key_list[key]
for aff in aff_list:
if aff['value'] == value:
return aff
return None
#
# Adds an affiliation of 'value' with 'key'
#
def affiliate(self, key, value):
# Locate key-value affiliation
aff = self._find_affiliation(key, value)
if aff is None:
# Create a (new) key-value affiliation
aff = {
'value': value,
'refcnt': 0,
}
aff_list = self.key_list[key]
aff_list.append(aff)
# Increment affiliation reference count
aff['refcnt'] += 1
return
#
# Removes an affiliation of 'value' with 'key'
#
def unaffiliate(self, key, value):
# Locate key-value affiliation
aff = self._find_affiliation(key, value)
if aff is None:
return
# Decrement affiliation reference count
aff['refcnt'] -= 1
# Destroy affiliation iff no outstanding references
if aff['refcnt'] <= 0:
aff_list = self.key_list[key]
aff_list.remove(aff)
return
#
# Lists all values affiliated with 'key'
#
# Note: The returned list is a set (contains no duplicates)
#
def list_affiliations(self, key):
aff_list = self.key_list[key]
value_list = []
for aff in aff_list:
value_list.append(aff['value'])
return value_list

View File

@ -1,60 +0,0 @@
# Copyright (C) 2016 Midokura SARL.
#
# 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 abc
import six
@six.add_metaclass(abc.ABCMeta)
class TaasBaseDriver(object):
def __init__(self, service_plugin):
self.service_plugin = service_plugin
@property
def service_type(self):
pass
@abc.abstractmethod
def create_tap_service_precommit(self, context):
pass
@abc.abstractmethod
def delete_tap_service_precommit(self, context):
pass
@abc.abstractmethod
def create_tap_flow_precommit(self, context):
pass
@abc.abstractmethod
def delete_tap_flow_precommit(self, context):
pass
@abc.abstractmethod
def create_tap_service_postcommit(self, context):
pass
@abc.abstractmethod
def delete_tap_service_postcommit(self, context):
pass
@abc.abstractmethod
def create_tap_flow_postcommit(self, context):
pass
@abc.abstractmethod
def delete_tap_flow_postcommit(self, context):
pass

View File

@ -1,67 +0,0 @@
# Copyright (C) 2016 Midokura SARL.
#
# 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.extensions import taas
from oslo_log import log
LOG = log.getLogger(__name__)
class ServiceDriverContext(object):
"""ServiceDriverContext context base class"""
def __init__(self, service_plugin, plugin_context):
self._plugin = service_plugin
self._plugin_context = plugin_context
class TapServiceContext(ServiceDriverContext):
def __init__(self, service_plugin, plugin_context, tap_service):
super(TapServiceContext, self).__init__(service_plugin, plugin_context)
self._tap_service = tap_service
self._tap_id_association = None
self._setup_tap_id_association(tap_service['id'])
def _setup_tap_id_association(self, tap_service_id):
try:
self._tap_id_association = self._plugin.get_tap_id_association(
self._plugin_context, tap_service_id)
except taas.TapServiceNotFound:
LOG.debug("Not found tap_ip_association for tap_service: %s",
tap_service_id)
@property
def tap_service(self):
return self._tap_service
@property
def tap_id_association(self):
return self._tap_id_association
@tap_id_association.setter
def tap_id_association(self, tap_id_association):
"""Set tap_id_association in context"""
self._tap_id_association = tap_id_association
class TapFlowContext(ServiceDriverContext):
def __init__(self, service_plugin, plugin_context, tap_flow):
super(TapFlowContext, self).__init__(service_plugin, plugin_context)
self._tap_flow = tap_flow
@property
def tap_flow(self):
return self._tap_flow

View File

@ -1,80 +0,0 @@
# Copyright (C) 2016 Midokura SARL.
# Copyright (C) 2015 Ericsson AB
# Copyright (c) 2015 Gigamon
#
# 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_lib import rpc as n_rpc
from oslo_log import log as logging
import oslo_messaging as messaging
LOG = logging.getLogger(__name__)
class TaasCallbacks(object):
"""Currently there are no callbacks to the Taas Plugin."""
def __init__(self, plugin):
super(TaasCallbacks, self).__init__()
self.plugin = plugin
return
class TaasAgentApi(object):
"""RPC calls to agent APIs"""
def __init__(self, topic, host):
self.host = host
target = messaging.Target(topic=topic, version='1.0')
self.client = n_rpc.get_client(target)
return
def create_tap_service(self, context, tap_service, host):
LOG.debug("In RPC Call for Create Tap Service: Host=%s, MSG=%s" %
(host, tap_service))
cctxt = self.client.prepare(fanout=True)
cctxt.cast(context, 'create_tap_service', tap_service=tap_service,
host=host)
return
def create_tap_flow(self, context, tap_flow_msg, host):
LOG.debug("In RPC Call for Create Tap Flow: Host=%s, MSG=%s" %
(host, tap_flow_msg))
cctxt = self.client.prepare(fanout=True)
cctxt.cast(context, 'create_tap_flow', tap_flow_msg=tap_flow_msg,
host=host)
return
def delete_tap_service(self, context, tap_service, host):
LOG.debug("In RPC Call for Delete Tap Service: Host=%s, MSG=%s" %
(host, tap_service))
cctxt = self.client.prepare(fanout=True)
cctxt.cast(context, 'delete_tap_service', tap_service=tap_service,
host=host)
return
def delete_tap_flow(self, context, tap_flow_msg, host):
LOG.debug("In RPC Call for Delete Tap Flow: Host=%s, MSG=%s" %
(host, tap_flow_msg))
cctxt = self.client.prepare(fanout=True)
cctxt.cast(context, 'delete_tap_flow', tap_flow_msg=tap_flow_msg,
host=host)
return

View File

@ -1,158 +0,0 @@
# Copyright (C) 2016 Midokura SARL.
# Copyright (C) 2015 Ericsson AB
# Copyright (c) 2015 Gigamon
#
# 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_lib import exceptions as n_exc
from neutron_lib import rpc as n_rpc
from neutron_taas.common import topics
from neutron_taas.services.taas import service_drivers
from neutron_taas.services.taas.service_drivers import taas_agent_api
from oslo_config import cfg
from oslo_log import log as logging
LOG = logging.getLogger(__name__)
class TaasRpcDriver(service_drivers.TaasBaseDriver):
"""Taas Rpc Service Driver class"""
def __init__(self, service_plugin):
LOG.debug("Loading TaasRpcDriver.")
super(TaasRpcDriver, self).__init__(service_plugin)
self.endpoints = [taas_agent_api.TaasCallbacks(service_plugin)]
self.conn = n_rpc.Connection()
self.conn.create_consumer(topics.TAAS_PLUGIN,
self.endpoints, fanout=False)
self.conn.consume_in_threads()
self.agent_rpc = taas_agent_api.TaasAgentApi(
topics.TAAS_AGENT,
cfg.CONF.host
)
return
def _get_taas_id(self, context, tf):
ts = self.service_plugin.get_tap_service(context,
tf['tap_service_id'])
taas_id = (self.service_plugin.get_tap_id_association(
context,
tap_service_id=ts['id']))['taas_id']
return taas_id
def create_tap_service_precommit(self, context):
ts = context.tap_service
tap_id_association = context._plugin.create_tap_id_association(
context._plugin_context, ts['id'])
context.tap_id_association = tap_id_association
def create_tap_service_postcommit(self, context):
"""Send tap service creation RPC message to agent.
This RPC message includes taas_id that is added vlan_range_start to
so that taas-ovs-agent can use taas_id as VLANID.
"""
# Get taas id associated with the Tap Service
ts = context.tap_service
tap_id_association = context.tap_id_association
taas_vlan_id = tap_id_association['taas_id']
port = self.service_plugin._get_port_details(context._plugin_context,
ts['port_id'])
host = port['binding:host_id']
rpc_msg = {'tap_service': ts,
'taas_id': taas_vlan_id,
'port': port}
self.agent_rpc.create_tap_service(context._plugin_context,
rpc_msg, host)
return
def delete_tap_service_precommit(self, context):
pass
def delete_tap_service_postcommit(self, context):
"""Send tap service deletion RPC message to agent.
This RPC message includes taas_id that is added vlan_range_start to
so that taas-ovs-agent can use taas_id as VLANID.
"""
ts = context.tap_service
tap_id_association = context.tap_id_association
taas_vlan_id = tap_id_association['taas_id']
try:
port = self.service_plugin._get_port_details(
context._plugin_context,
ts['port_id'])
host = port['binding:host_id']
except n_exc.PortNotFound:
# if not found, we just pass to None
port = None
host = None
rpc_msg = {'tap_service': ts,
'taas_id': taas_vlan_id,
'port': port}
self.agent_rpc.delete_tap_service(context._plugin_context,
rpc_msg, host)
return
def create_tap_flow_precommit(self, context):
pass
def create_tap_flow_postcommit(self, context):
"""Send tap flow creation RPC message to agent."""
tf = context.tap_flow
taas_id = self._get_taas_id(context._plugin_context, tf)
# Extract the host where the source port is located
port = self.service_plugin._get_port_details(context._plugin_context,
tf['source_port'])
host = port['binding:host_id']
port_mac = port['mac_address']
# Send RPC message to both the source port host and
# tap service(destination) port host
rpc_msg = {'tap_flow': tf,
'port_mac': port_mac,
'taas_id': taas_id,
'port': port}
self.agent_rpc.create_tap_flow(context._plugin_context, rpc_msg, host)
return
def delete_tap_flow_precommit(self, context):
pass
def delete_tap_flow_postcommit(self, context):
"""Send tap flow deletion RPC message to agent."""
tf = context.tap_flow
taas_id = self._get_taas_id(context._plugin_context, tf)
# Extract the host where the source port is located
port = self.service_plugin._get_port_details(context._plugin_context,
tf['source_port'])
host = port['binding:host_id']
port_mac = port['mac_address']
# Send RPC message to both the source port host and
# tap service(destination) port host
rpc_msg = {'tap_flow': tf,
'port_mac': port_mac,
'taas_id': taas_id,
'port': port}
self.agent_rpc.delete_tap_flow(context._plugin_context, rpc_msg, host)
return

View File

@ -1,211 +0,0 @@
# Copyright (C) 2016 Midokura SARL.
# Copyright (C) 2015 Ericsson AB
# Copyright (c) 2015 Gigamon
#
# 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.db import servicetype_db as st_db
from neutron.services import provider_configuration as pconf
from neutron.services import service_base
from neutron_lib.callbacks import events
from neutron_lib.callbacks import registry
from neutron_lib.callbacks import resources
from neutron_lib import exceptions as n_exc
from neutron_taas.common import constants
from neutron_taas.db import taas_db
from neutron_taas.extensions import taas as taas_ex
from neutron_taas.services.taas.service_drivers import (service_driver_context
as sd_context)
from oslo_log import log as logging
from oslo_utils import excutils
LOG = logging.getLogger(__name__)
def add_provider_configuration(type_manager, service_type):
type_manager.add_provider_configuration(
service_type,
pconf.ProviderConfiguration('neutron_taas'))
@registry.has_registry_receivers
class TaasPlugin(taas_db.Taas_db_Mixin):
supported_extension_aliases = ["taas"]
path_prefix = "/taas"
def __init__(self):
LOG.debug("TAAS PLUGIN INITIALIZED")
self.service_type_manager = st_db.ServiceTypeManager.get_instance()
add_provider_configuration(self.service_type_manager, constants.TAAS)
self._load_drivers()
self.driver = self._get_driver_for_provider(self.default_provider)
return
def _load_drivers(self):
"""Loads plugin-drivers specified in configuration."""
self.drivers, self.default_provider = service_base.load_drivers(
'TAAS', self)
def _get_driver_for_provider(self, provider):
if provider in self.drivers:
return self.drivers[provider]
raise n_exc.Invalid("Error retrieving driver for provider %s" %
provider)
def create_tap_service(self, context, tap_service):
LOG.debug("create_tap_service() called")
t_s = tap_service['tap_service']
tenant_id = t_s['tenant_id']
port_id = t_s['port_id']
# Get port details
port = self._get_port_details(context, port_id)
# Check if the port is owned by the tenant.
if port['tenant_id'] != tenant_id:
raise taas_ex.PortDoesNotBelongToTenant()
# Extract the host where the port is located
host = port['binding:host_id']
if host is not None:
LOG.debug("Host on which the port is created = %s" % host)
else:
LOG.debug("Host could not be found, Port Binding disbaled!")
# Create tap service in the db model
with context.session.begin(subtransactions=True):
ts = super(TaasPlugin, self).create_tap_service(context,
tap_service)
driver_context = sd_context.TapServiceContext(self, context, ts)
self.driver.create_tap_service_precommit(driver_context)
try:
self.driver.create_tap_service_postcommit(driver_context)
except Exception:
with excutils.save_and_reraise_exception():
LOG.error("Failed to create tap service on driver,"
"deleting tap_service %s", ts['id'])
super(TaasPlugin, self).delete_tap_service(context, ts['id'])
return ts
def delete_tap_service(self, context, id):
LOG.debug("delete_tap_service() called")
# Get all the tap Flows that are associated with the Tap service
# and delete them as well
t_f_collection = self.get_tap_flows(
context,
filters={'tap_service_id': [id]}, fields=['id'])
for t_f in t_f_collection:
self.delete_tap_flow(context, t_f['id'])
with context.session.begin(subtransactions=True):
ts = self.get_tap_service(context, id)
driver_context = sd_context.TapServiceContext(self, context, ts)
super(TaasPlugin, self).delete_tap_service(context, id)
self.driver.delete_tap_service_precommit(driver_context)
try:
self.driver.delete_tap_service_postcommit(driver_context)
except Exception:
with excutils.save_and_reraise_exception():
LOG.error("Failed to delete tap service on driver. "
"tap_sevice: %s", id)
def create_tap_flow(self, context, tap_flow):
LOG.debug("create_tap_flow() called")
t_f = tap_flow['tap_flow']
tenant_id = t_f['tenant_id']
# Check if the tenant id of the source port is the same as the
# tenant_id of the tap service we are attaching it to.
ts = self.get_tap_service(context, t_f['tap_service_id'])
ts_tenant_id = ts['tenant_id']
if tenant_id != ts_tenant_id:
raise taas_ex.TapServiceNotBelongToTenant()
# create tap flow in the db model
with context.session.begin(subtransactions=True):
tf = super(TaasPlugin, self).create_tap_flow(context, tap_flow)
driver_context = sd_context.TapFlowContext(self, context, tf)
self.driver.create_tap_flow_precommit(driver_context)
try:
self.driver.create_tap_flow_postcommit(driver_context)
except Exception:
with excutils.save_and_reraise_exception():
LOG.error("Failed to create tap flow on driver,"
"deleting tap_flow %s", tf['id'])
super(TaasPlugin, self).delete_tap_flow(context, tf['id'])
return tf
def delete_tap_flow(self, context, id):
LOG.debug("delete_tap_flow() called")
with context.session.begin(subtransactions=True):
tf = self.get_tap_flow(context, id)
driver_context = sd_context.TapFlowContext(self, context, tf)
super(TaasPlugin, self).delete_tap_flow(context, id)
self.driver.delete_tap_flow_precommit(driver_context)
try:
self.driver.delete_tap_flow_postcommit(driver_context)
except Exception:
with excutils.save_and_reraise_exception():
with excutils.save_and_reraise_exception():
LOG.error("Failed to delete tap flow on driver. "
"tap_flow: %s", id)
@registry.receives(resources.PORT, [events.PRECOMMIT_DELETE])
def handle_delete_port(self, resource, event, trigger, context, **kwargs):
deleted_port = kwargs['port']
if not deleted_port:
LOG.error("TaaS: Handle Delete Port: Invalid port object received")
return
deleted_port_id = deleted_port['id']
LOG.info("TaaS: Handle Delete Port: %s", deleted_port_id)
# Get list of configured tap-services
t_s_collection = self.get_tap_services(
context,
filters={'port_id': [deleted_port_id]}, fields=['id'])
for t_s in t_s_collection:
try:
self.delete_tap_service(context, t_s['id'])
except taas_ex.TapServiceNotFound:
LOG.debug("Not found tap_service: %s", t_s['id'])
t_f_collection = self.get_tap_flows(
context,
filters={'source_port': [deleted_port_id]}, fields=['id'])
for t_f in t_f_collection:
try:
self.delete_tap_flow(context, t_f['id'])
except taas_ex.TapFlowNotFound:
LOG.debug("Not found tap_flow: %s", t_f['id'])

View File

@ -1,120 +0,0 @@
# Copyright 2015 NEC 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 neutron_taas._i18n import _
from neutronclient.common import extension
from neutronclient.common import utils
from neutronclient.neutron import v2_0 as neutronv20
def _add_updatable_args(parser):
parser.add_argument(
'--name',
help=_('Name of this Tap flow.'))
parser.add_argument(
'--description',
help=_('Description for this Tap flow.'))
def _updatable_args2body(parsed_args, body):
neutronv20.update_dict(parsed_args, body, ['name', 'description'])
class TapFlow(extension.NeutronClientExtension):
# Define required variables for resource operations.
resource = 'tap_flow'
resource_plural = '%ss' % resource
object_path = '/taas/%s' % resource_plural
resource_path = '/taas/%s/%%s' % resource_plural
versions = ['2.0']
class ListTapFlow(extension.ClientExtensionList, TapFlow):
"""List tap flows."""
shell_command = 'tap-flow-list'
list_columns = ['id', 'name', 'source_port', 'tap_service_id', 'status']
pagination_support = True
sorting_support = True
class CreateTapFlow(extension.ClientExtensionCreate, TapFlow):
"""Create a tap flow."""
shell_command = 'tap-flow-create'
list_columns = ['id', 'name', 'direction', 'source_port']
def add_known_arguments(self, parser):
_add_updatable_args(parser)
parser.add_argument(
'--port',
required=True,
metavar="SOURCE_PORT",
help=_('Source port to which the Tap Flow is connected.'))
parser.add_argument(
'--tap-service',
required=True,
metavar="TAP_SERVICE",
help=_('Tap Service to which the Tap Flow belongs.'))
parser.add_argument(
'--direction',
required=True,
metavar="DIRECTION",
choices=['IN', 'OUT', 'BOTH'],
type=utils.convert_to_uppercase,
help=_('Direction of the Tap flow.'))
def args2body(self, parsed_args):
client = self.get_client()
source_port = neutronv20.find_resourceid_by_name_or_id(
client, 'port',
parsed_args.port)
tap_service_id = neutronv20.find_resourceid_by_name_or_id(
client, 'tap_service',
parsed_args.tap_service)
body = {'source_port': source_port,
'tap_service_id': tap_service_id}
neutronv20.update_dict(parsed_args, body, ['tenant_id', 'direction'])
_updatable_args2body(parsed_args, body)
return {self.resource: body}
class DeleteTapFlow(extension.ClientExtensionDelete, TapFlow):
"""Delete a tap flow."""
shell_command = 'tap-flow-delete'
class ShowTapFlow(extension.ClientExtensionShow, TapFlow):
"""Show a tap flow."""
shell_command = 'tap-flow-show'
class UpdateTapFlow(extension.ClientExtensionUpdate, TapFlow):
"""Update a tap flow."""
shell_command = 'tap-flow-update'
list_columns = ['id', 'name']
def add_known_arguments(self, parser):
_add_updatable_args(parser)
def args2body(self, parsed_args):
body = {}
_updatable_args2body(parsed_args, body)
return {self.resource: body}

View File

@ -1,105 +0,0 @@
# Copyright 2015 NEC 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 neutron_taas._i18n import _
from neutronclient.common import extension
from neutronclient.neutron import v2_0 as neutronv20
def _add_updatable_args(parser):
parser.add_argument(
'--name',
help=_('Name of this Tap service.'))
parser.add_argument(
'--description',
help=_('Description for this Tap service.'))
def _updatable_args2body(parsed_args, body):
neutronv20.update_dict(parsed_args, body, ['name', 'description'])
class TapService(extension.NeutronClientExtension):
# Define required variables for resource operations.
resource = 'tap_service'
resource_plural = '%ss' % resource
object_path = '/taas/%s' % resource_plural
resource_path = '/taas/%s/%%s' % resource_plural
versions = ['2.0']
class ListTapService(extension.ClientExtensionList, TapService):
"""List tap services."""
shell_command = 'tap-service-list'
list_columns = ['id', 'name', 'port', 'status']
pagination_support = True
sorting_support = True
class CreateTapService(extension.ClientExtensionCreate, TapService):
"""Create a tap service."""
shell_command = 'tap-service-create'
list_columns = ['id', 'name', 'port']
def add_known_arguments(self, parser):
_add_updatable_args(parser)
parser.add_argument(
'--port',
dest='port_id',
required=True,
metavar="PORT",
help=_('Port to which the Tap service is connected.'))
def args2body(self, parsed_args):
client = self.get_client()
port_id = neutronv20.find_resourceid_by_name_or_id(
client, 'port',
parsed_args.port_id)
body = {'port_id': port_id}
if parsed_args.tenant_id:
body['tenant_id'] = parsed_args.tenant_id
_updatable_args2body(parsed_args, body)
return {self.resource: body}
class DeleteTapService(extension.ClientExtensionDelete, TapService):
"""Delete a tap service."""
shell_command = 'tap-service-delete'
class ShowTapService(extension.ClientExtensionShow, TapService):
"""Show a tap service."""
shell_command = 'tap-service-show'
class UpdateTapService(extension.ClientExtensionUpdate, TapService):
"""Update a tap service."""
shell_command = 'tap-service-update'
list_columns = ['id', 'name']
def add_known_arguments(self, parser):
_add_updatable_args(parser)
def args2body(self, parsed_args):
body = {}
_updatable_args2body(parsed_args, body)
return {self.resource: body}

View File

@ -1,61 +0,0 @@
# Copyright 2016 VMware, Inc
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_config import cfg
from neutron.db.migration.alembic_migrations import external
from neutron.db.migration import cli as migration
from neutron.tests.functional.db import test_migrations
from neutron.tests.unit import testlib_api
from neutron_taas.db import head
# EXTERNAL_TABLES should contain all names of tables that are not related to
# current repo.
EXTERNAL_TABLES = set(external.TABLES)
VERSION_TABLE = 'taas_alembic_version'
class _TestModelsMigrationsTAAS(test_migrations._TestModelsMigrations):
def db_sync(self, engine):
cfg.CONF.set_override('connection', engine.url, group='database')
for conf in migration.get_alembic_configs():
self.alembic_config = conf
self.alembic_config.neutron_config = cfg.CONF
migration.do_alembic_command(conf, 'upgrade', 'heads')
def get_metadata(self):
return head.get_metadata()
def include_object(self, object_, name, type_, reflected, compare_to):
if type_ == 'table' and (name.startswith('alembic') or
name == VERSION_TABLE or
name in EXTERNAL_TABLES):
return False
if type_ == 'index' and reflected and name.startswith("idx_autoinc_"):
return False
return True
class TestModelsMigrationsMysql(testlib_api.MySQLTestCaseMixin,
_TestModelsMigrationsTAAS,
testlib_api.SqlTestCaseLight):
pass
class TestModelsMigrationsPostgresql(testlib_api.PostgreSQLTestCaseMixin,
_TestModelsMigrationsTAAS,
testlib_api.SqlTestCaseLight):
pass

View File

@ -1,208 +0,0 @@
# Copyright 2016 VMware, Inc.
# 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.tests.unit import testlib_api
from neutron_lib import context
from oslo_utils import importutils
from oslo_utils import uuidutils
from neutron_taas.db import taas_db
from neutron_taas.extensions import taas
DB_PLUGIN_KLAAS = 'neutron.db.db_base_plugin_v2.NeutronDbPluginV2'
_uuid = uuidutils.generate_uuid
class TaaSDbTestCase(testlib_api.SqlTestCase):
"""Unit test for TaaS DB support."""
def setUp(self):
super(TaaSDbTestCase, self).setUp()
self.ctx = context.get_admin_context()
self.mixin = taas_db.Taas_db_Mixin()
self.plugin = importutils.import_object(DB_PLUGIN_KLAAS)
self.tenant_id = 'fake-tenant-id'
def _get_tap_service_data(self, name='ts-1', port_id=None):
port_id = port_id or _uuid()
return {"tap_service": {"name": name,
"tenant_id": self.tenant_id,
"description": "test tap service",
"port_id": port_id}}
def _get_tap_flow_data(self, tap_service_id, name='tf-1',
direction='BOTH', source_port=None):
source_port = source_port or _uuid()
return {"tap_flow": {"name": name,
"tenant_id": self.tenant_id,
"description": "test tap flow",
"tap_service_id": tap_service_id,
"source_port": source_port,
"direction": direction}}
def _get_tap_service(self, tap_service_id):
"""Helper method to retrieve tap service."""
with self.ctx.session.begin(subtransactions=True):
return self.mixin.get_tap_service(self.ctx, tap_service_id)
def _get_tap_services(self):
"""Helper method to retrieve all tap services."""
with self.ctx.session.begin(subtransactions=True):
return self.mixin.get_tap_services(self.ctx)
def _create_tap_service(self, tap_service):
"""Helper method to create tap service."""
with self.ctx.session.begin(subtransactions=True):
return self.mixin.create_tap_service(self.ctx, tap_service)
def _update_tap_service(self, tap_service_id, tap_service):
"""Helper method to update tap service."""
with self.ctx.session.begin(subtransactions=True):
return self.mixin.update_tap_service(self.ctx,
tap_service_id,
tap_service)
def _delete_tap_service(self, tap_service_id):
"""Helper method to delete tap service."""
with self.ctx.session.begin(subtransactions=True):
return self.mixin.delete_tap_service(self.ctx, tap_service_id)
def _get_tap_flow(self, tap_flow_id):
"""Helper method to retrieve tap flow."""
with self.ctx.session.begin(subtransactions=True):
return self.mixin.get_tap_flow(self.ctx, tap_flow_id)
def _get_tap_flows(self):
"""Helper method to retrieve all tap flows."""
with self.ctx.session.begin(subtransactions=True):
return self.mixin.get_tap_flows(self.ctx)
def _create_tap_flow(self, tap_flow):
"""Helper method to create tap flow."""
with self.ctx.session.begin(subtransactions=True):
return self.mixin.create_tap_flow(self.ctx, tap_flow)
def _update_tap_flow(self, tap_flow_id, tap_flow):
"""Helper method to update tap flow."""
with self.ctx.session.begin(subtransactions=True):
return self.mixin.update_tap_flow(self.ctx, tap_flow_id, tap_flow)
def _delete_tap_flow(self, tap_flow_id):
"""Helper method to delete tap flow."""
with self.ctx.session.begin(subtransactions=True):
return self.mixin.delete_tap_flow(self.ctx, tap_flow_id)
def test_tap_service_get(self):
"""Test to retrieve a tap service from the database."""
name = 'test-tap-service'
data = self._get_tap_service_data(name=name)
result = self._create_tap_service(data)
get_result = self._get_tap_service(result['id'])
self.assertEqual(name, get_result['name'])
def test_tap_service_create(self):
"""Test to create a tap service in the database."""
name = 'test-tap-service'
port_id = _uuid()
data = self._get_tap_service_data(name=name, port_id=port_id)
result = self._create_tap_service(data)
self.assertEqual(name, result['name'])
self.assertEqual(port_id, result['port_id'])
def test_tap_service_list(self):
"""Test to retrieve all tap services from the database."""
name_1 = "ts-1"
data_1 = self._get_tap_service_data(name=name_1)
name_2 = "ts-2"
data_2 = self._get_tap_service_data(name=name_2)
self._create_tap_service(data_1)
self._create_tap_service(data_2)
tap_services = self._get_tap_services()
self.assertEqual(2, len(tap_services))
def test_tap_service_update(self):
"""Test to update a tap service in the database."""
original_name = "ts-1"
updated_name = "ts-1-got-updated"
data = self._get_tap_service_data(name=original_name)
ts = self._create_tap_service(data)
updated_data = self._get_tap_service_data(name=updated_name)
ts_updated = self._update_tap_service(ts['id'], updated_data)
self.assertEqual(updated_name, ts_updated['name'])
def test_tap_service_delete(self):
"""Test to delete a tap service from the database."""
data = self._get_tap_service_data()
result = self._create_tap_service(data)
self._delete_tap_service(result['id'])
self.assertRaises(taas.TapServiceNotFound,
self._get_tap_service, result['id'])
def test_tap_flow_get(self):
"""Test to retrieve a tap flow from the database."""
ts_data = self._get_tap_service_data()
ts = self._create_tap_service(ts_data)
tf_name = 'test-tap-flow'
tf_data = self._get_tap_flow_data(tap_service_id=ts['id'],
name=tf_name)
tf = self._create_tap_flow(tf_data)
get_tf = self._get_tap_flow(tf['id'])
self.assertEqual(tf_name, get_tf['name'])
def test_tap_flow_create(self):
"""Test to create a tap flow in the database."""
ts_data = self._get_tap_service_data()
ts = self._create_tap_service(ts_data)
tf_name = 'test-tap-flow'
tf_direction = 'IN'
tf_source_port = _uuid()
tf_data = self._get_tap_flow_data(tap_service_id=ts['id'],
name=tf_name,
source_port=tf_source_port,
direction=tf_direction)
tf = self._create_tap_flow(tf_data)
self.assertEqual(tf_name, tf['name'])
self.assertEqual(tf_direction, tf['direction'])
self.assertEqual(tf_source_port, tf['source_port'])
def test_tap_flow_list(self):
"""Test to retrieve all tap flows from the database."""
ts_data = self._get_tap_service_data()
ts = self._create_tap_service(ts_data)
tf_1_name = "tf-1"
tf_1_data = self._get_tap_flow_data(tap_service_id=ts['id'],
name=tf_1_name)
tf_2_name = "tf-2"
tf_2_data = self._get_tap_flow_data(tap_service_id=ts['id'],
name=tf_2_name)
self._create_tap_flow(tf_1_data)
self._create_tap_flow(tf_2_data)
tap_flows = self._get_tap_flows()
self.assertEqual(2, len(tap_flows))
def test_tap_flow_delete(self):
"""Test to delete a tap flow from the database."""
ts_data = self._get_tap_service_data()
ts = self._create_tap_service(ts_data)
tf_name = "test-tap-flow"
tf_data = self._get_tap_flow_data(tap_service_id=ts['id'],
name=tf_name)
tf = self._create_tap_flow(tf_data)
self._delete_tap_flow(tf['id'])
self.assertRaises(taas.TapFlowNotFound,
self._get_tap_flow, tf['id'])

View File

@ -1,104 +0,0 @@
# Copyright 2017 FUJITSU LABORATORIES LTD.
# 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 copy
import mock
from webob import exc
from oslo_utils import uuidutils
from neutron.tests.unit.api.v2 import test_base as test_api_v2
from neutron.tests.unit.extensions import base as test_api_v2_extension
from neutron_taas.extensions import taas as taas_ext
_uuid = uuidutils.generate_uuid
_get_path = test_api_v2._get_path
TAP_SERVICE_PATH = 'taas/tap_services'
TAP_FLOW_PATH = 'taas/tap_flows'
class TaasExtensionTestCase(test_api_v2_extension.ExtensionTestCase):
fmt = 'json'
def setUp(self):
super(TaasExtensionTestCase, self).setUp()
self.setup_extension(
'neutron_taas.extensions.taas.TaasPluginBase',
'TAAS',
taas_ext.Taas,
'taas',
plural_mappings={}
)
def test_create_tap_service(self):
tenant_id = _uuid()
tap_service_data = {
'tenant_id': tenant_id,
'name': 'MyTap',
'description': 'This is my tap service',
'port_id': _uuid(),
'project_id': tenant_id,
}
data = {'tap_service': tap_service_data}
expected_ret_val = copy.copy(data['tap_service'])
expected_ret_val.update({'id': _uuid()})
instance = self.plugin.return_value
instance.create_tap_service.return_value = expected_ret_val
res = self.api.post(_get_path(TAP_SERVICE_PATH, fmt=self.fmt),
self.serialize(data),
content_type='application/%s' % self.fmt)
instance.create_tap_service.assert_called_with(
mock.ANY,
tap_service=data)
self.assertEqual(exc.HTTPCreated.code, res.status_int)
res = self.deserialize(res)
self.assertIn('tap_service', res)
self.assertEqual(expected_ret_val, res['tap_service'])
def test_delete_tap_service(self):
self._test_entity_delete('tap_service')
def test_create_tap_flow(self):
tenant_id = _uuid()
tap_flow_data = {
'tenant_id': tenant_id,
'name': 'MyTapFlow',
'description': 'This is my tap flow',
'direction': 'BOTH',
'tap_service_id': _uuid(),
'source_port': _uuid(),
'project_id': tenant_id,
}
data = {'tap_flow': tap_flow_data}
expected_ret_val = copy.copy(data['tap_flow'])
expected_ret_val.update({'id': _uuid()})
instance = self.plugin.return_value
instance.create_tap_flow.return_value = expected_ret_val
res = self.api.post(_get_path(TAP_FLOW_PATH, fmt=self.fmt),
self.serialize(data),
content_type='application/%s' % self.fmt)
instance.create_tap_flow.assert_called_with(
mock.ANY,
tap_flow=data)
self.assertEqual(exc.HTTPCreated.code, res.status_int)
res = self.deserialize(res)
self.assertIn('tap_flow', res)
self.assertEqual(expected_ret_val, res['tap_flow'])
def test_delete_tap_flow(self):
self._test_entity_delete('tap_flow')

View File

@ -1,276 +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 contextlib
import mock
import testtools
from neutron_lib import context
from neutron_lib import rpc as n_rpc
from neutron_lib.utils import net as n_utils
from oslo_config import cfg
from oslo_utils import uuidutils
from neutron.tests.unit import testlib_api
import neutron_taas.db.taas_db # noqa
import neutron_taas.extensions.taas as taas_ext
from neutron_taas.services.taas.service_drivers import taas_agent_api
from neutron_taas.services.taas import taas_plugin
class DummyError(Exception):
pass
class TestTaasPlugin(testlib_api.SqlTestCase):
def setUp(self):
super(TestTaasPlugin, self).setUp()
mock.patch.object(n_rpc, 'Connection', auto_spec=True).start()
mock.patch.object(taas_agent_api,
'TaasCallbacks', auto_spec=True).start()
mock.patch.object(taas_agent_api,
'TaasAgentApi', auto_spec=True).start()
self.driver = mock.MagicMock()
mock.patch('neutron.services.service_base.load_drivers',
return_value=({'dummy_provider': self.driver},
'dummy_provider')).start()
mock.patch('neutron.db.servicetype_db.ServiceTypeManager.get_instance',
return_value=mock.MagicMock()).start()
self._plugin = taas_plugin.TaasPlugin()
self._context = context.get_admin_context()
self._project_id = self._tenant_id = 'tenant-X'
self._network_id = uuidutils.generate_uuid()
self._host_id = 'host-A'
self._port_id = uuidutils.generate_uuid()
self._port_details = {
'tenant_id': self._tenant_id,
'binding:host_id': self._host_id,
'mac_address': n_utils.get_random_mac(
'fa:16:3e:00:00:00'.split(':')),
}
self._tap_service = {
'tenant_id': self._tenant_id,
'name': 'MyTap',
'description': 'This is my tap service',
'port_id': self._port_id,
'project_id': self._project_id,
}
self._tap_flow = {
'description': 'This is my tap flow',
'direction': 'BOTH',
'name': 'MyTapFlow',
'source_port': self._port_id,
'tenant_id': self._tenant_id,
'project_id': self._project_id,
}
@contextlib.contextmanager
def tap_service(self):
req = {
'tap_service': self._tap_service,
}
with mock.patch.object(self._plugin, '_get_port_details',
return_value=self._port_details):
yield self._plugin.create_tap_service(self._context, req)
self._tap_service['id'] = mock.ANY
self._tap_service['status'] = 'ACTIVE'
self.driver.assert_has_calls([
mock.call.create_tap_service_precommit(mock.ANY),
mock.call.create_tap_service_postcommit(mock.ANY),
])
pre_args = self.driver.create_tap_service_precommit.call_args[0][0]
self.assertEqual(self._context, pre_args._plugin_context)
self.assertEqual(self._tap_service, pre_args.tap_service)
post_args = self.driver.create_tap_service_postcommit.call_args[0][0]
self.assertEqual(self._context, post_args._plugin_context)
self.assertEqual(self._tap_service, post_args.tap_service)
@contextlib.contextmanager
def tap_flow(self, tap_service, tenant_id=None):
self._tap_flow['tap_service_id'] = tap_service
if tenant_id is not None:
self._tap_flow['tenant_id'] = tenant_id
req = {
'tap_flow': self._tap_flow,
}
with mock.patch.object(self._plugin, '_get_port_details',
return_value=self._port_details):
yield self._plugin.create_tap_flow(self._context, req)
self._tap_flow['id'] = mock.ANY
self._tap_flow['status'] = 'ACTIVE'
self._tap_service['id'] = mock.ANY
self.driver.assert_has_calls([
mock.call.create_tap_flow_precommit(mock.ANY),
mock.call.create_tap_flow_postcommit(mock.ANY),
])
pre_args = self.driver.create_tap_flow_precommit.call_args[0][0]
self.assertEqual(self._context, pre_args._plugin_context)
self.assertEqual(self._tap_flow, pre_args.tap_flow)
post_args = self.driver.create_tap_flow_postcommit.call_args[0][0]
self.assertEqual(self._context, post_args._plugin_context)
self.assertEqual(self._tap_flow, post_args.tap_flow)
def test_create_tap_service(self):
with self.tap_service():
pass
def test_verify_taas_id_reused(self):
# make small range id
cfg.CONF.set_override("vlan_range_start", 1, group="taas")
cfg.CONF.set_override("vlan_range_end", 3, group="taas")
with self.tap_service() as ts_1, self.tap_service() as ts_2, \
self.tap_service() as ts_3, self.tap_service() as ts_4:
ts_id_1 = ts_1['id']
ts_id_2 = ts_2['id']
ts_id_3 = ts_3['id']
tap_id_assoc_1 = self._plugin.create_tap_id_association(
self._context, ts_id_1)
tap_id_assoc_2 = self._plugin.create_tap_id_association(
self._context, ts_id_2)
self.assertEqual(set([1, 2]), set([tap_id_assoc_1['taas_id'],
tap_id_assoc_2['taas_id']]))
with testtools.ExpectedException(taas_ext.TapServiceLimitReached):
self._plugin.create_tap_id_association(
self._context,
ts_4['id']
)
# free an tap_id and verify could reallocate same taas id
self._plugin.delete_tap_service(self._context, ts_id_1)
tap_id_assoc_3 = self._plugin.create_tap_id_association(
self._context, ts_id_3)
self.assertEqual(set([1, 2]), set([tap_id_assoc_3['taas_id'],
tap_id_assoc_2['taas_id']]))
def test_create_tap_service_wrong_tenant_id(self):
self._port_details['tenant_id'] = 'other-tenant'
with testtools.ExpectedException(taas_ext.PortDoesNotBelongToTenant), \
self.tap_service():
pass
self.assertEqual([], self.driver.mock_calls)
def test_create_tap_service_reach_limit(self):
# TODO(Yoichiro):Need to move this test to taas_rpc test
pass
def test_create_tap_service_failed_on_service_driver(self):
attr = {'create_tap_service_postcommit.side_effect': DummyError}
self.driver.configure_mock(**attr)
with testtools.ExpectedException(DummyError):
req = {
'tap_service': self._tap_service,
}
with mock.patch.object(self._plugin, '_get_port_details',
return_value=self._port_details):
self._plugin.create_tap_service(self._context, req)
def test_delete_tap_service(self):
with self.tap_service() as ts:
self._plugin.delete_tap_service(self._context, ts['id'])
self.driver.assert_has_calls([
mock.call.delete_tap_service_precommit(mock.ANY),
mock.call.delete_tap_service_postcommit(mock.ANY),
])
pre_args = self.driver.delete_tap_service_precommit.call_args[0][0]
self.assertEqual(self._context, pre_args._plugin_context)
self.assertEqual(self._tap_service, pre_args.tap_service)
post_args = self.driver.delete_tap_service_postcommit.call_args[0][0]
self.assertEqual(self._context, post_args._plugin_context)
self.assertEqual(self._tap_service, post_args.tap_service)
def test_delete_tap_service_with_flow(self):
with self.tap_service() as ts, \
self.tap_flow(tap_service=ts['id']):
self._plugin.delete_tap_service(self._context, ts['id'])
self.driver.assert_has_calls([
mock.call.delete_tap_flow_precommit(mock.ANY),
mock.call.delete_tap_flow_postcommit(mock.ANY),
mock.call.delete_tap_service_precommit(mock.ANY),
mock.call.delete_tap_service_postcommit(mock.ANY),
])
pre_args = self.driver.delete_tap_flow_precommit.call_args[0][0]
self.assertEqual(self._context, pre_args._plugin_context)
self.assertEqual(self._tap_flow, pre_args.tap_flow)
post_args = self.driver.delete_tap_flow_postcommit.call_args[0][0]
self.assertEqual(self._context, post_args._plugin_context)
self.assertEqual(self._tap_flow, post_args.tap_flow)
pre_args = self.driver.delete_tap_service_precommit.call_args[0][0]
self.assertEqual(self._context, pre_args._plugin_context)
self.assertEqual(self._tap_service, pre_args.tap_service)
post_args = self.driver.delete_tap_service_postcommit.call_args[0][0]
self.assertEqual(self._context, post_args._plugin_context)
self.assertEqual(self._tap_service, post_args.tap_service)
def test_delete_tap_service_non_existent(self):
with testtools.ExpectedException(taas_ext.TapServiceNotFound):
self._plugin.delete_tap_service(self._context, 'non-existent')
def test_delete_tap_service_failed_on_service_driver(self):
attr = {'delete_tap_service_postcommit.side_effect': DummyError}
self.driver.configure_mock(**attr)
with self.tap_service() as ts:
with testtools.ExpectedException(DummyError):
self._plugin.delete_tap_service(self._context, ts['id'])
def test_create_tap_flow(self):
with self.tap_service() as ts, self.tap_flow(tap_service=ts['id']):
pass
def test_create_tap_flow_wrong_tenant_id(self):
with self.tap_service() as ts, \
testtools.ExpectedException(taas_ext.TapServiceNotBelongToTenant), \
self.tap_flow(tap_service=ts['id'], tenant_id='other-tenant'):
pass
def test_create_tap_flow_failed_on_service_driver(self):
with self.tap_service() as ts:
attr = {'create_tap_flow_postcommit.side_effect': DummyError}
self.driver.configure_mock(**attr)
with testtools.ExpectedException(DummyError):
self._tap_flow['tap_service_id'] = ts['id']
req = {
'tap_flow': self._tap_flow,
}
with mock.patch.object(self._plugin, '_get_port_details',
return_value=self._port_details):
self._plugin.create_tap_flow(self._context, req)
def test_delete_tap_flow(self):
with self.tap_service() as ts, \
self.tap_flow(tap_service=ts['id']) as tf:
self._plugin.delete_tap_flow(self._context, tf['id'])
self._tap_flow['id'] = tf['id']
self.driver.assert_has_calls([
mock.call.delete_tap_flow_precommit(mock.ANY),
mock.call.delete_tap_flow_postcommit(mock.ANY),
])
pre_args = self.driver.delete_tap_flow_precommit.call_args[0][0]
self.assertEqual(self._context, pre_args._plugin_context)
self.assertEqual(self._tap_flow, pre_args.tap_flow)
post_args = self.driver.delete_tap_flow_postcommit.call_args[0][0]
self.assertEqual(self._context, post_args._plugin_context)
self.assertEqual(self._tap_flow, post_args.tap_flow)
def test_delete_tap_flow_failed_on_service_driver(self):
with self.tap_service() as ts, \
self.tap_flow(tap_service=ts['id']) as tf:
attr = {'delete_tap_flow_postcommit.side_effect': DummyError}
self.driver.configure_mock(**attr)
with testtools.ExpectedException(DummyError):
self._plugin.delete_tap_flow(self._context, tf['id'])

View File

@ -1,114 +0,0 @@
# Copyright 2015 NEC 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.
#
import mock
import sys
from neutron_taas.taas_client import tapflow
from neutronclient import shell
from neutronclient.tests.unit import test_cli20
class CLITestV20TapFlowJSON(test_cli20.CLITestV20Base):
resource = 'tap_flow'
resource_plural = '%ss' % resource
def setUp(self):
self._mock_extension_loading()
super(CLITestV20TapFlowJSON, self).setUp()
self.resources = self.resource_plural
self.register_non_admin_status_resource(self.resource)
def _create_patch(self, name, func=None):
patcher = mock.patch(name)
thing = patcher.start()
return thing
def _mock_extension_loading(self):
ext_pkg = 'neutronclient.common.extension'
contrib = self._create_patch(ext_pkg + '._discover_via_entry_points')
contrib.return_value = [("_tap_flow", tapflow)]
return contrib
def test_ext_cmd_loaded(self):
neutron_shell = shell.NeutronShell('2.0')
extension_cmd = {'tap-flow-create': tapflow.CreateTapFlow,
'tap-flow-delete': tapflow.DeleteTapFlow,
'tap-flow-show': tapflow.ShowTapFlow,
'tap-flow-list': tapflow.ListTapFlow}
for cmd_name, cmd_class in extension_cmd.items():
found = neutron_shell.command_manager.find_command([cmd_name])
self.assertEqual(cmd_class, found[0])
def _test_create_tap_flow(self, port_id="random_port",
service_id="random_service",
direction="BOTH", arg_attr=None,
name_attr=None, val_attr=None,
name=''):
# Common definition for creating Tap flow
arg_attr = arg_attr or []
name_attr = name_attr or []
val_attr = val_attr or []
cmd = tapflow.CreateTapFlow(test_cli20.MyApp(sys.stdout), None)
tenant_id = 'my-tenant'
my_id = 'my-id'
args = ['--tenant-id', tenant_id,
'--port', port_id,
'--tap-service', service_id,
'--direction', direction] + arg_attr
pos_names = ['source_port', 'tap_service_id', 'direction'] + name_attr
pos_values = [port_id, service_id, direction] + val_attr
self._test_create_resource(self.resource, cmd, name, my_id, args,
pos_names, pos_values,
tenant_id=tenant_id)
def test_create_tap_flow_mandatory_params(self):
self._test_create_tap_flow()
def test_create_tap_flow_all_params(self):
name = 'dummyTapFlow'
description = 'Create a dummy tap flow'
self._test_create_tap_flow(name=name,
arg_attr=[
'--name', name,
'--description', description],
name_attr=['name', 'description'],
val_attr=[name, description])
def test_delete_tap_flow(self):
# Delete tap_flow: myid.
cmd = tapflow.DeleteTapFlow(test_cli20.MyApp(sys.stdout), None)
myid = 'myid'
args = [myid]
self._test_delete_resource(self.resource, cmd, myid, args)
def test_update_tap_flow(self):
# Update tap_flow: myid --name myname.
cmd = tapflow.UpdateTapFlow(test_cli20.MyApp(sys.stdout), None)
self._test_update_resource(self.resource, cmd, 'myid',
['myid', '--name', 'myname'],
{'name': 'myname'})
def test_list_tap_flows(self):
# List tap_flows.
cmd = tapflow.ListTapFlow(test_cli20.MyApp(sys.stdout), None)
self._test_list_resources(self.resources, cmd, True)
def test_show_tap_flow(self):
# Show tap_flow: --fields id --fields name myid.
cmd = tapflow.ShowTapFlow(test_cli20.MyApp(sys.stdout), None)
args = ['--fields', 'id', '--fields', 'name', self.test_id]
self._test_show_resource(self.resource, cmd, self.test_id,
args, ['id', 'name'])

View File

@ -1,113 +0,0 @@
# Copyright 2015 NEC 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.
#
import mock
import sys
from neutron_taas.taas_client import tapservice
from neutronclient import shell
from neutronclient.tests.unit import test_cli20
class CLITestV20TapServiceJSON(test_cli20.CLITestV20Base):
resource = 'tap_service'
resource_plural = '%ss' % resource
def setUp(self):
self._mock_extension_loading()
super(CLITestV20TapServiceJSON, self).setUp()
self.resources = self.resource_plural
self.register_non_admin_status_resource(self.resource)
def _create_patch(self, name, func=None):
patcher = mock.patch(name)
thing = patcher.start()
return thing
def _mock_extension_loading(self):
ext_pkg = 'neutronclient.common.extension'
contrib = self._create_patch(ext_pkg + '._discover_via_entry_points')
contrib.return_value = [("_tap_service", tapservice)]
return contrib
def test_ext_cmd_loaded(self):
neutron_shell = shell.NeutronShell('2.0')
extension_cmd = {'tap-service-create': tapservice.CreateTapService,
'tap-service-delete': tapservice.DeleteTapService,
'tap-service-show': tapservice.ShowTapService,
'tap-service-list': tapservice.ListTapService}
for cmd_name, cmd_class in extension_cmd.items():
found = neutron_shell.command_manager.find_command([cmd_name])
self.assertEqual(cmd_class, found[0])
def _test_create_tap_service(self, port_id="random_port",
name='',
args_attr=None, position_names_attr=None,
position_values_attr=None):
cmd = tapservice.CreateTapService(test_cli20.MyApp(sys.stdout), None)
args_attr = args_attr or []
position_names_attr = position_names_attr or []
position_values_attr = position_values_attr or []
name = name
tenant_id = 'my-tenant'
my_id = 'my-id'
args = ['--tenant-id', tenant_id,
'--port', port_id] + args_attr
position_names = ['port_id'] + position_names_attr
position_values = [port_id] + position_values_attr
self._test_create_resource(self.resource, cmd, name, my_id, args,
position_names, position_values,
tenant_id=tenant_id)
def test_create_tap_service_mandatory_params(self):
# Create tap_service: --port random_port
self._test_create_tap_service()
def test_create_tap_service_all_params(self):
# Create tap_service with mandatory params, --name and --description
name = 'new-tap-service'
description = 'This defines a new tap-service'
args_attr = ['--name', name, '--description', description]
position_names_attr = ['name', 'description']
position_val_attr = [name, description]
self._test_create_tap_service(name=name, args_attr=args_attr,
position_names_attr=position_names_attr,
position_values_attr=position_val_attr)
def test_delete_tap_service(self):
# Delete tap_service: myid.
cmd = tapservice.DeleteTapService(test_cli20.MyApp(sys.stdout), None)
myid = 'myid'
args = [myid]
self._test_delete_resource(self.resource, cmd, myid, args)
def test_update_tap_service(self):
# Update tap_service: myid --name myname.
cmd = tapservice.UpdateTapService(test_cli20.MyApp(sys.stdout), None)
self._test_update_resource(self.resource, cmd, 'myid',
['myid', '--name', 'myname'],
{'name': 'myname'})
def test_list_tap_services(self):
# List tap_services.
cmd = tapservice.ListTapService(test_cli20.MyApp(sys.stdout), None)
self._test_list_resources(self.resources, cmd, True)
def test_show_tap_service(self):
# Show tap_service: --fields id --fields name myid.
cmd = tapservice.ShowTapService(test_cli20.MyApp(sys.stdout), None)
args = ['--fields', 'id', '--fields', 'name', self.test_id]
self._test_show_resource(self.resource, cmd, self.test_id,
args, ['id', 'name'])

View File

@ -15,7 +15,7 @@
from tempest.api.network import base
from neutron_taas.tests.tempest_plugin.tests import taas_client
from neutron_taas_tempest_plugin.tests import taas_client
class BaseTaaSTest(taas_client.TaaSClientMixin, base.BaseNetworkTest):

View File

@ -19,7 +19,7 @@ from tempest import config
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
from neutron_taas.tests.tempest_plugin.tests.api import base
from neutron_taas_tempest_plugin.tests.api import base
CONF = config.CONF

View File

@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
from neutron_taas.tests.tempest_plugin.tests.scenario import manager
from neutron_taas_tempest_plugin.tests.scenario import manager
class TaaSScenarioTest(manager.NetworkScenarioTest):

View File

@ -17,7 +17,7 @@ from tempest.common import utils
from tempest import config
from tempest.lib import decorators
from neutron_taas.tests.tempest_plugin.tests.scenario import base
from neutron_taas_tempest_plugin.tests.scenario import base
CONF = config.CONF

View File

@ -17,7 +17,7 @@ from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib.common.utils import test_utils
from neutron_taas.tests.tempest_plugin.services import client
from neutron_taas_tempest_plugin.services import client
CONF = config.CONF

View File

@ -1,6 +0,0 @@
[DEFAULT]
# The list of modules to copy from oslo-incubator.git
# The base module to hold the copy of openstack.common
base=neutron_taas

View File

@ -1,15 +0,0 @@
- hosts: primary
tasks:
- name: Copy files from {{ ansible_user_dir }}/workspace/ on node
synchronize:
src: '{{ ansible_user_dir }}/workspace/'
dest: '{{ zuul.executor.log_root }}'
mode: pull
copy_links: true
verify_host: true
rsync_opts:
- --include=/logs/**
- --include=*/
- --exclude=*
- --prune-empty-dirs

Some files were not shown because too many files have changed in this diff Show More