Retire repo

This repository was never used, retire it.

Depends-On: https://review.opendev.org/673543
Change-Id: I40d5e939bb0daca094fce64f0662018188b5984e
This commit is contained in:
Andreas Jaeger 2019-07-30 17:29:45 +02:00
parent 1ab6c6a3a0
commit 8fb398dc08
53 changed files with 10 additions and 2744 deletions

17
.gitignore vendored
View File

@ -1,17 +0,0 @@
# Python
*.pyc
# Packages
.eggs
*.egg-info
build/
dist/
# Testing
.tox
.testrepository
# Editors
*~
.*.swp
.*sw?

View File

@ -1,4 +0,0 @@
[DEFAULT]
test_command=OS_STDOUT_CAPTURE=1 OS_STDERR_CAPTURE=1 OS_LOG_CAPTURE=1 ${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./wan_qos/tests/unit} $LISTOPT $IDOPTION | cat
test_id_option=--load-list $IDFILE
test_list_option=--list

View File

@ -0,0 +1,10 @@
This project is no longer maintained.
The contents of this repository are still available in the Git
source code management system. To see the contents of this
repository before it reached its end of life, please check out the
previous commit with "git checkout HEAD^1".
For any further questions, please email
openstack-discuss@lists.openstack.org or join #openstack-dev on
Freenode.

View File

@ -1,25 +0,0 @@
# The order of packages is significant, because pip processes them in the order
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
pbr>=2.0.0 # Apache-2.0
Babel>=2.3.4 # BSD
kazoo>=2.2 # Apache-2.0
ovs>=2.7.0 # Apache-2.0
pyzmq>=14.3.1 # LGPL+BSD
ryu>=4.9 # Apache-2.0
SQLAlchemy!=1.1.5,!=1.1.6,!=1.1.7,!=1.1.8,>=1.0.10 # MIT
alembic>=0.8.10 # MIT
neutron-lib>=1.3.0 # Apache-2.0
oslo.config>=3.22.0 # Apache-2.0
oslo.db>=4.19.0 # Apache-2.0
oslo.i18n>=2.1.0 # Apache-2.0
oslo.log>=3.22.0 # Apache-2.0
oslo.reports>=0.6.0 # Apache-2.0
oslo.serialization>=1.10.0 # Apache-2.0
crc16>=0.1.1 # LGPLv3+
netaddr!=0.7.16,>=0.7.13 # BSD
six>=1.9.0 # MIT
httplib2>=0.7.5 # MIT
WebOb>=1.7.1 # MIT

View File

@ -1,39 +0,0 @@
[metadata]
name = tc-as-a-service
summary = APIs and implementations to support TC as a Service
description-file =
README.rst
author = OpenStack
author-email = openstack-dev@lists.openstack.org
home-page = http://www.openstack.org/
classifier =
Environment :: OpenStack
Intended Audience :: Information Technology
Intended Audience :: System Administrators
License :: OSI Approved :: Apache Software License
Operating System :: POSIX :: Linux
Programming Language :: Python
Programming Language :: Python :: 2
Programming Language :: Python :: 2.7
Programming Language :: Python :: 3
Programming Language :: Python :: 3.4
Programming Language :: Python :: 3.5
[files]
packages =
wan_qos
data_files =
etc/neutron =
etc/wan_qos_agent.ini
etc/wan_qos_plugin.ini
[entry_points]
console_scripts =
neutron-wan-qos-agent = wan_qos.cmd.eventlet.agent:main
neutron.db.alembic_migrations =
wan-qos = wan_qos.db.migration:alembic_migrations
neutronclient.extension =
wan_tc_filter = wan_qos.wanqos_client._wantcfilter
wan_tc_device = wan_qos.wanqos_client._wantcdevice
wan_tc_class = wan_qos.wanqos_client._wantcclass
wan_tc = wan_qos.wanqos_client._wantc

View File

@ -1,27 +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.
# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
import setuptools
# In python < 2.7.4, a lazy loading of package `pbr` will break
# setuptools if some other modules registered functions in `atexit`.
# solution from: http://bugs.python.org/issue15881#msg170215
try:
import multiprocessing # noqa
except ImportError:
pass
setuptools.setup(
setup_requires=['pbr>=2.0'],
pbr=True)

View File

@ -1,14 +0,0 @@
# The order of packages is significant, because pip processes them in the order
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0
mock>=2.0 # BSD
python-subunit>=0.0.18 # Apache-2.0/BSD
os-testr>=0.8.0 # Apache-2.0
oslotest>=1.10.0 # Apache-2.0
testrepository>=0.0.18 # Apache-2.0/BSD
testresources>=0.2.4 # Apache-2.0/BSD
testscenarios>=0.4 # Apache-2.0/BSD
testtools>=1.4.0 # MIT

View File

@ -1,53 +0,0 @@
#!/bin/sh
# Many of neutron's repos suffer from the problem of depending on neutron,
# but it not existing on pypi.
# This wrapper for tox's package installer will use the existing package
# if it exists, else use zuul-cloner if that program exists, else grab it
# from neutron master via a hard-coded URL. That last case should only
# happen with devs running unit tests locally.
# From the tox.ini config page:
# install_command=ARGV
# default:
# pip install {opts} {packages}
ZUUL_CLONER=/usr/zuul-env/bin/zuul-cloner
neutron_installed=$(echo "import neutron" | python 2>/dev/null ; echo $?)
BRANCH_NAME=master
set -ex
cwd=$(/bin/pwd)
CONSTRAINTS_FILE=$1
shift
install_cmd="pip install"
if [ $CONSTRAINTS_FILE != "unconstrained" ]; then
install_cmd="$install_cmd -c$CONSTRAINTS_FILE"
fi
if [ $neutron_installed -eq 0 ]; then
echo "ALREADY INSTALLED" > /tmp/tox_install.txt
echo "Neutron already installed; using existing package"
elif [ -x "$ZUUL_CLONER" ]; then
echo "ZUUL CLONER" > /tmp/tox_install.txt
cd /tmp
export ZUUL_BRANCH=${ZUUL_BRANCH-$BRANCH}
$ZUUL_CLONER --cache-dir \
/opt/git \
--branch $BRANCH_NAME \
git://git.openstack.org \
openstack/neutron
cd openstack/neutron
$install_cmd -e .
cd "$cwd"
else
echo "PIP HARDCODE" > /tmp/tox_install.txt
$install_cmd -U -egit+https://git.openstack.org/openstack/neutron@$BRANCH_NAME#egg=neutron
fi
$install_cmd -U $*
exit $?

51
tox.ini
View File

@ -1,51 +0,0 @@
[tox]
minversion = 1.6
envlist = pep8,py27,py35
skipsdist = True
[testenv]
# Note the hash seed is set to 0 until neutron can be tested with a
# random hash seed successfully.
setenv = VIRTUAL_ENV={envdir}
PYTHONHASHSEED=0
PYTHONWARNINGS=default::DeprecationWarning
usedevelop = True
install_command = {toxinidir}/tools/tox_install.sh {env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages}
deps = -r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
whitelist_externals = sh
commands =
ostestr '{posargs}'
# sh tools/pretty_tox.sh '{posargs}'
[testenv:pep8]
commands =
flake8
neutron-db-manage --subproject dragonflow check_migration
[testenv:venv]
commands = {posargs}
[flake8]
# E126 continuation line over-indented for hanging indent
# H404 multi line docstring should start with a summary
# H405 multi line docstring summary not separated with an empty line
# N530 Direct neutron imports not allowed
# N531 log message does not translate
ignore = E126,H404,H405,N530,N531
# H904: Delay string interpolations at logging calls
# H203: Use assertIs(Not)None to check for None
enable-extensions=H904,H203
show-source = true
exclude = ./.*,dist,doc,build,tools
[testenv:pylint]
deps =
{[testenv]deps}
pylint
commands =
pylint --rcfile=.pylintrc --output-format=colorized {posargs:neutron}
[hacking]
#import_exceptions = wan_qos._i18n
local-check-factory = neutron_lib.hacking.checks.factory

View File

View File

@ -1,58 +0,0 @@
# Copyright 2016 Huawei corp.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import abc
import six
@six.add_metaclass(abc.ABCMeta)
class AgentInterface(object):
"Base class that defines the contract for TC agent"
@abc.abstractmethod
def clear_all(self):
"Delete all traffic control configurations"
@abc.abstractmethod
def set_ports(self, in_port, out_port):
"Set the names of the LAN and WAN facing ports"
@abc.abstractmethod
def set_root_queue(self, tc_dict):
"""Sets the root qdisc with its max rate of the WAN link to be set
as upper limit
"""
@abc.abstractmethod
def create_traffic_class(self, tc_dict):
"Add traffic class using traffic information from the dictionary."
@abc.abstractmethod
def update_traffic_class(self, tc_dict):
"Update traffic control using information from tc dictionary."
@abc.abstractmethod
def remove_traffic_class(self, tc_dict):
"Update traffic control using information from tc dictionary."
@abc.abstractmethod
def create_filter(self, tc_dict):
"""Create traffic filter that is used to route packets to the
right queue
"""
@abc.abstractmethod
def remove_filter(self, tc_dict):
"Remove traffic filter"

View File

@ -1,58 +0,0 @@
# Copyright 2016 Huawei corp.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import sys
import eventlet
from neutron.common import config as common_config
from neutron.conf.agent import common as config
from neutron import service as neutron_service
from oslo_config import cfg
from oslo_service import service
from wan_qos.common import topics
eventlet.monkey_patch()
WANTC_OPTS = [
cfg.StrOpt('lan_port_name',
default='eth0',
help="The name of the port facing the LAN"),
cfg.StrOpt('lan_max_rate',
default='10mbit',
help="The maximum rate of the LAN port"),
cfg.StrOpt('wan_port_name',
default='eth1',
help="The name of the port facing the WAN"),
cfg.StrOpt('wan_max_rate',
default='10mbit',
help="The maximum rate of the WAN port")
]
def main():
cfg.CONF.register_opts(WANTC_OPTS, 'WANTC')
common_config.init(sys.argv[1:])
config.setup_logging()
server = neutron_service.Service.create(
binary='tc_agent2',
topic=topics.TC_AGENT,
report_interval=10,
manager='wan_qos.agent.tc_manager.TcAgentManager')
service.launch(cfg.CONF, server).wait()
if __name__ == '__main__':
main()

View File

@ -1,119 +0,0 @@
# Copyright 2016 Huawei corp.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import subprocess
from neutron_lib import exceptions
from oslo_log import log as logging
from wan_qos.agent import agent_api
LOG = logging.getLogger(__name__)
class TcDriver(agent_api.AgentInterface):
def __init__(self):
self.ports = {}
def set_ports(self, lan_port, wan_port):
self.ports['lan_port'] = lan_port
self.ports['wan_port'] = wan_port
def get_ports(self):
return self.ports
def clear_all(self):
for port in self.ports.values():
subprocess.call('sudo tc qdisc del dev %s root' % port, shell=True)
def set_root_queue(self, tc_dict):
subprocess.check_call('sudo tc qdisc add dev %s handle 1: root htb' %
self.ports[tc_dict['port_side']], shell=True)
class_str = 'sudo tc class add dev %s parent 1: classid 1:1 ' \
'htb rate %s ceil %s'
subprocess.check_call(class_str % (self.ports[tc_dict['port_side']],
str(tc_dict['max_rate']),
str(tc_dict['max_rate'])),
shell=True)
def create_traffic_class(self, tc_dict):
"""Create new traffic class.
Parameters:
port_side - lan_port / wan_port
parent - the parent class
child - the class id
min - minimum traffic rate (CIR)
max - maximum traffic rate. if not provide, the maximum rate will
be limitted by parent maximum rate.
"""
LOG.debug('got request for new class: %s', tc_dict)
tc_dict['command'] = 'add'
self._create_or_update_class(tc_dict)
LOG.debug('new class created.')
def update_traffic_class(self, tc_dict):
tc_dict['command'] = 'change'
self._create_or_update_class(tc_dict)
def remove_traffic_class(self, tc_dict, with_filter=False):
if with_filter:
self.remove_filter(tc_dict)
cmd = 'sudo tc class del dev %s classid 1:%s' % (
self.ports[tc_dict['port_side']],
tc_dict['child']
)
subprocess.check_call(cmd, shell=True)
def _create_or_update_class(self, tc_dict):
cmd = 'sudo tc class %s dev %s parent 1:%s classid 1:%s htb' % (
tc_dict['command'],
self.ports[tc_dict['port_side']],
tc_dict['parent'], tc_dict['child']
)
if 'min' in tc_dict:
cmd += ' rate %s' % tc_dict['min']
else:
cmd += ' rate 1kbit'
if 'max' in tc_dict:
cmd += ' ceil %s' % tc_dict['max']
subprocess.check_call(cmd, shell=True)
def create_filter(self, tc_dict):
if tc_dict['protocol'] == 'vxlan':
self._create_vxlan_filter(tc_dict)
return
raise exceptions.BadRequest(msg='Protocol not supported')
def _create_vxlan_filter(self, tc_dict):
vni = tc_dict['match'].split('=')[1]
cmd = 'sudo tc filter add dev %s parent 1:0' % (
self.ports[tc_dict['port_side']])
cmd += ' protocol ip prio 1 u32'
cmd += ' match ip protocol 17 0xFF' # UDP
cmd += ' match u16 0x12B5 0xFFFF at 22' # VxLAN port
cmd += ' match u32 0x%0.6X00 0xFFFFFF00 at 32' % int(vni)
cmd += ' flowid 1:%s' % tc_dict['child']
LOG.debug('creating filter: %s', cmd)
subprocess.check_call(cmd, shell=True)
def remove_filter(self, tc_dict):
cmd = 'sudo tc filter del dev %s ' % self.ports[tc_dict['port_side']]
cmd += ' parent 1:0 protocol ip prio 1 u32'
cmd += ' flowid 1:%s' % tc_dict['child']
subprocess.check_call(cmd, shell=True)

View File

@ -1,168 +0,0 @@
# Copyright 2016 Huawei corp.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_config import cfg
from oslo_log import log as logging
import oslo_messaging as messaging
from neutron import manager
from neutron_lib import context as ctx
from neutron_lib import exceptions
from wan_qos.agent import tc_driver
from wan_qos.common import api
from wan_qos.common import topics
LOG = logging.getLogger(__name__)
class TcAgentManager(manager.Manager):
target = messaging.Target(version='1.0')
def __init__(self, host=None, conf=None):
self.agent = tc_driver.TcDriver()
if not conf:
self.conf = cfg.CONF
else:
self.conf = conf
if not host:
self.host = self.conf.host
else:
self.host = host
lan_port = self.conf.WANTC.lan_port_name
wan_port = self.conf.WANTC.wan_port_name
self.agent.set_ports(lan_port, wan_port)
self.plugin_rpc = api.TcPluginApi(host, topics.TC_PLUGIN)
self.plugin_rpc.agent_up_notification(ctx.get_admin_context(),
self.agent.get_ports())
def init_host(self):
self.agent.clear_all()
tc_dict = {
'port_side': 'lan_port',
'max_rate': self.conf.WANTC.lan_max_rate
}
self.agent.set_root_queue(tc_dict)
tc_dict = {
'port_side': 'wan_port',
'max_rate': self.conf.WANTC.wan_max_rate
}
self.agent.set_root_queue(tc_dict)
context = ctx.get_admin_context()
agent_conf = self.plugin_rpc.get_configuration_from_db(
context)
class_tree = agent_conf['class_tree']
if class_tree['id'] == 'root':
self.init_child_classes(class_tree['child_list'])
if 'filters' in agent_conf:
for filter in agent_conf['filters']:
self.create_wtc_filter(context, filter)
return
raise exceptions.InvalidInput(error_message='Did not get root class')
def init_child_classes(self, child_list):
for child in child_list:
self.create_wtc_class(None, child)
self.init_child_classes(child['child_list'])
def after_start(self):
LOG.info("WAN QoS agent started")
def periodic_tasks(self, context, raise_on_error=False):
LOG.info("periodic task")
self.plugin_rpc.device_heartbeat(context, self.host)
def create_wtc_class(self, context, wtc_class_dict):
LOG.debug('got request for new class: %s', wtc_class_dict)
class_dict = {
'parent': wtc_class_dict['parent_class_ext_id'],
'child': wtc_class_dict['class_ext_id']
}
if wtc_class_dict['min']:
class_dict['min'] = wtc_class_dict['min']
if wtc_class_dict['max']:
class_dict['max'] = wtc_class_dict['max']
if (
wtc_class_dict['direction'] == 'in' or
wtc_class_dict['direction'] == 'both'
):
class_dict['port_side'] = 'lan_port'
self._create_wtc_class(class_dict)
if (
wtc_class_dict['direction'] == 'out' or
wtc_class_dict['direction'] == 'both'
):
class_dict['port_side'] = 'wan_port'
self._create_wtc_class(class_dict)
def _create_wtc_class(self, class_dict):
self.agent.create_traffic_class(class_dict)
def delete_wtc_class(self, context, wtc_class_tree):
for child in wtc_class_tree['child_list']:
self.delete_wtc_class(context, child)
self._delete_wtc_class(wtc_class_tree)
def _delete_wtc_class(self, wtc_class):
tc_dict = {
'parent': wtc_class['parent_class_ext_id'],
'child': wtc_class['class_ext_id']
}
if wtc_class['direction'] == 'in' or wtc_class['direction'] == 'both':
tc_dict['port_side'] = 'lan_port'
self.agent.remove_traffic_class(tc_dict)
if wtc_class['direction'] == 'out' or wtc_class['direction'] == 'both':
tc_dict['port_side'] = 'wan_port'
self.agent.remove_traffic_class(tc_dict)
def create_wtc_filter(self, context, wtc_filter):
wtc_class = self.plugin_rpc.get_class_by_id(context,
wtc_filter['class_id'])
tc_dict = {
'child': wtc_class['class_ext_id'],
'protocol': wtc_filter['protocol'],
'match': wtc_filter['match']
}
port_side = wtc_class['direction']
if port_side == 'both' or port_side == 'in':
tc_dict['port_side'] = 'lan_port'
self.agent.create_filter(tc_dict)
if port_side == 'both' or port_side == 'out':
tc_dict['port_side'] = 'wan_port'
self.agent.create_filter(tc_dict)
def delete_wtc_filter(self, context, wtc_filter):
wtc_class = wtc_filter['class']
port_side = wtc_class['direction']
tc_dict = {
'child': wtc_class['class_ext_id']
}
if port_side == 'both' or port_side == 'in':
tc_dict['port_side'] = 'lan_port'
self.agent.remove_filter(tc_dict)
if port_side == 'both' or port_side == 'out':
tc_dict['port_side'] = 'wan_port'
self.agent.remove_filter(tc_dict)

View File

@ -1,20 +0,0 @@
# Copyright 2016 Huawei corp.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from wan_qos.agent import tc_agent
def main():
tc_agent.main()

View File

@ -1,81 +0,0 @@
# Copyright 2016 Huawei corp.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import oslo_messaging
from neutron.common import rpc as n_rpc
from wan_qos.common import topics
class TcPluginApi(object):
def __init__(self, host, topic=topics.TC_PLUGIN):
self.host = host
target = oslo_messaging.Target(topic=topic, version='1.0')
self.client = n_rpc.get_client(target)
def agent_up_notification(self, context, ports):
cctxt = self.client.prepare()
host_info = {
'host': self.host,
'lan_port': ports['lan_port'],
'wan_port': ports['wan_port']
}
cctxt.cast(context, 'agent_up_notification',
host_info=host_info)
def device_heartbeat(self, context, host):
cctxt = self.client.prepare()
cctxt.cast(context, 'device_heartbeat',
host=host)
def get_configuration_from_db(self, context):
cctxt = self.client.prepare()
return cctxt.call(context, 'get_configuration_from_db', host=self.host)
def get_class_by_id(self, context, id):
cctxt = self.client.prepare()
return cctxt.call(context, 'get_class_by_id', id=id)
class TcAgentApi(object):
def __init__(self, host, topic=topics.TC_AGENT):
self.host = host
target = oslo_messaging.Target(topic=topic, version='1.0')
self.client = n_rpc.get_client(target)
def create_wtc_class(self, context, wtc_class_dict):
cctxt = self.client.prepare()
return cctxt.call(context,
'create_wtc_class',
wtc_class_dict=wtc_class_dict)
def delete_wtc_class(self, context, wtc_class_tree):
cctxt = self.client.prepare()
return cctxt.call(context,
'delete_wtc_class',
wtc_class_tree=wtc_class_tree)
def create_wtc_filter(self, context, wtc_filter):
cctxt = self.client.prepare()
return cctxt.call(context,
'create_wtc_filter',
wtc_filter=wtc_filter)
def delete_wtc_filter(self, context, wtc_filter):
cctxt = self.client.prepare()
return cctxt.call(context,
'delete_wtc_filter',
wtc_filter=wtc_filter)

View File

@ -1,28 +0,0 @@
# Copyright 2016 Huawei corp.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
WANTC = 'WANTC'
WAN_TC_DEVICE = 'wan_tc_device'
WAN_TC_DEVICE_PATH = 'wan-tc-devices'
WAN_TC_CLASS = 'wan_tc_class'
WAN_TC_CLASS_PATH = 'wan-tc-classs'
WAN_TC_FILTER = 'wan_tc_filter'
WAN_TC_FILTER_PATH = 'wan-tc-filters'
WAN_TC = 'wan_tc'
WAN_TC_PATH = 'wan-tcs'

View File

@ -1,17 +0,0 @@
# Copyright 2016 Huawei corp.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
TC_AGENT = 'wan_qos_agent'
TC_PLUGIN = 'wan_qos_plugin'

View File

View File

@ -1,99 +0,0 @@
# Copyright 2015 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.
#
from logging import config as logging_config
from alembic import context
from neutron_lib.db import model_base
from oslo_config import cfg
from oslo_db.sqlalchemy import session
import sqlalchemy as sa
from sqlalchemy import event
from neutron.db.migration.alembic_migrations import external
from neutron.db.migration.models import head # noqa
MYSQL_ENGINE = None
WANTC_VERSION_TABLE = 'wantc_alembic_version'
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 include_object(object, name, type_, reflected, compare_to):
if type_ == 'table' and name in external.TABLES:
return False
else:
return True
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['include_object'] = include_object
kwargs['version_table'] = WANTC_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,
include_object=include_object,
version_table=WANTC_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,36 +0,0 @@
# Copyright ${create_date.year} <PUT YOUR NAME/COMPANY HERE>
#
# 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.
#
"""${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,84 +0,0 @@
# Copyright 2017 <PUT YOUR NAME/COMPANY HERE>
#
# 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.
#
"""first rev
Revision ID: 45194b1d3492
Revises: None
Create Date: 2017-01-04 13:46:13.433909
"""
# revision identifiers, used by Alembic.
revision = '45194b1d3492'
down_revision = None
from alembic import op
import sqlalchemy as sa
def upgrade():
op.create_table('wan_tc_class',
sa.Column('id', sa.String(length=36), nullable=False),
sa.Column('parent', sa.String(length=36)),
sa.Column('device_id', sa.String(length=36)),
sa.Column('direction', sa.String(length=4),
nullable=False),
sa.Column('project_id', sa.String(length=36)),
sa.Column('class_ext_id', sa.Integer()),
sa.Column('parent_class_ext_id', sa.Integer()),
sa.Column('min', sa.String(length=15)),
sa.Column('max', sa.String(length=15)),
sa.PrimaryKeyConstraint('id')
)
op.create_foreign_key(
'fk_wtc_class',
'wan_tc_class', 'wan_tc_class',
['parent'], ['id'], ondelete='CASCADE'
)
op.create_table('wan_tc_filter',
sa.Column('id', sa.String(length=36), nullable=False),
sa.Column('project_id', sa.String(length=36)),
sa.Column('class_id', sa.String(length=36),
nullable=False),
sa.Column('network', sa.String(length=36)),
sa.Column('protocol', sa.String(length=15)),
sa.Column('match', sa.String(length=15)),
sa.PrimaryKeyConstraint('id')
)
op.create_foreign_key(
'fk_wan_tc__filter_class',
'wan_tc_filter', 'wan_tc_class',
['class_id'], ['id'],
)
op.create_foreign_key(
'fk_wan_tc_filter_networks',
'wan_tc_filter', 'networks',
['network'], ['id'],
)
op.create_table(
'wan_tc_device',
sa.Column('id', sa.String(length=36), nullable=False),
sa.Column('host', sa.String(100), nullable=False),
sa.Column('lan_port', sa.String(15), nullable=False),
sa.Column('wan_port', sa.String(15), nullable=False),
sa.Column('uptime', sa.DateTime()),
sa.Column('heartbeat_timestamp', sa.DateTime())
)

View File

@ -1,60 +0,0 @@
# Copyright 2016 Huawei corp.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import sqlalchemy as sa
from neutron_lib.db import model_base
class WanTcDevice(model_base.BASEV2,
model_base.HasId):
__tablename__ = 'wan_tc_device'
host = sa.Column(sa.String(100), nullable=False)
lan_port = sa.Column(sa.String(15), nullable=False)
wan_port = sa.Column(sa.String(15), nullable=False)
uptime = sa.Column(sa.DateTime())
heartbeat_timestamp = sa.Column(sa.DateTime())
class WanTcClass(model_base.BASEV2,
model_base.HasId, model_base.HasProject):
__tablename__ = 'wan_tc_class'
device_id = sa.Column(sa.String(36),
sa.ForeignKey('wan_tc_device.id',
ondelete='CASCADE'),
nullable=True)
direction = sa.Column(sa.String(4), nullable=False)
class_ext_id = sa.Column(sa.Integer)
parent = sa.Column(sa.String(36),
sa.ForeignKey('wan_tc_class.id',
ondelete='CASCADE'),
nullable=True)
parent_class_ext_id = sa.Column(sa.Integer)
min = sa.Column(sa.String(15))
max = sa.Column(sa.String(15))
class WanTcFilter(model_base.BASEV2,
model_base.HasId, model_base.HasProject):
__tablename__ = 'wan_tc_filter'
class_id = sa.Column(sa.String(36),
sa.ForeignKey('wan_tc_class.id',
ondelete='CASCADE'),
nullable=False)
network = sa.Column(sa.String(36),
sa.ForeignKey('networks.id',
ondelete='CASCADE'))
protocol = sa.Column(sa.String(15))
match = sa.Column(sa.String(15))

View File

@ -1,345 +0,0 @@
# Copyright 2016 Huawei corp.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import threading
from neutron_lib import exceptions
from neutron_lib import context as ctx
from oslo_log import log as logging
from oslo_utils import timeutils
from oslo_utils import uuidutils
from wan_qos.db.models import wan_tc as models
LOG = logging.getLogger(__name__)
class WanTcDb(object):
_last_class_ext_id = None
def __init__(self):
self._lock = threading.Lock()
self._initialize_tables()
def _initialize_tables(self):
context = ctx.get_admin_context()
root_class = context.session.query(models.WanTcClass).filter_by(
id='root').first()
if not root_class:
with context.session.begin(subtransactions=True):
root_class = models.WanTcClass(
id='root',
class_ext_id=1,
direction='both'
)
context.session.add(root_class)
def agent_up_notification(self, context, host_info):
device = context.session.query(models.WanTcDevice).filter_by(
host=host_info['host']
).first()
with context.session.begin(subtransactions=True):
if not device:
LOG.debug('New device connected: %s', host_info)
now = timeutils.utcnow()
wan_tc_device = models.WanTcDevice(
id=uuidutils.generate_uuid(),
host=host_info['host'],
lan_port=host_info['lan_port'],
wan_port=host_info['wan_port'],
uptime=now,
heartbeat_timestamp=now
)
return context.session.add(wan_tc_device)
else:
LOG.debug('updating uptime for device: %s', host_info['host'])
device.uptime = timeutils.utcnow()
def device_heartbeat(self, context, host):
device = context.session.query(models.WanTcDevice).filter_by(
host=host
).first()
if device:
with context.session.begin(subtransactions=True):
device.heartbeat_timestamp = timeutils.utcnow()
else:
LOG.error('Got heartbeat for non-existing device: %s', host)
def get_all_devices(self, context, filters=None,
fields=None,
sorts=None, limit=None, marker=None,
page_reverse=False):
marker_obj = self._get_marker_obj(
context, 'wan_tc_device', limit, marker)
return self._get_collection(context, models.WanTcDevice,
self._device_to_dict,
filters=filters, fields=fields,
sorts=sorts, limit=limit,
marker_obj=marker_obj,
page_reverse=page_reverse)
def get_last_class_ext_id(self, context):
self._lock.acquire()
if not self._last_class_ext_id:
last_class_ext_id_db = context.session.query(
models.WanTcClass.class_ext_id).order_by(
models.WanTcClass.class_ext_id.desc()).first()
if last_class_ext_id_db:
self._last_class_ext_id, = last_class_ext_id_db
else:
self._last_class_ext_id = 10
self._last_class_ext_id += 1
next_id = self._last_class_ext_id
self._lock.release()
return next_id
def create_wan_tc_class(self, context, wtc_class):
wtc_class_db = models.WanTcClass(
id=uuidutils.generate_uuid(),
direction=wtc_class['direction'],
class_ext_id=self.get_last_class_ext_id(context)
)
if 'parent' in wtc_class and wtc_class['parent'] != '':
parent = wtc_class['parent']
parent_class = self.get_class_by_id(context, parent)
if not parent_class:
raise exceptions.BadRequest(msg='invalid parent id')
wtc_class_db.parent = parent
wtc_class_db.parent_class_ext_id = parent_class['class_ext_id']
else:
wtc_class_db.parent = 'root'
wtc_class_db.parent_class_ext_id = 1
with context.session.begin(subtransactions=True):
if 'min' in wtc_class:
wtc_class_db.min = wtc_class['min']
if 'max' in wtc_class:
wtc_class_db.max = wtc_class['max']
context.session.add(wtc_class_db)
class_dict = self._class_to_dict(wtc_class_db)
class_dict['parent_class_ext_id'] = wtc_class_db.parent_class_ext_id
return class_dict
def delete_wtc_class(self, context, id):
wtc_class_db = context.session.query(models.WanTcClass).filter_by(
id=id).first()
if wtc_class_db:
with context.session.begin(subtransactions=True):
context.session.delete(wtc_class_db)
def get_class_by_id(self, context, id):
wtc_class = context.session.query(models.WanTcClass).filter_by(
id=id).first()
if wtc_class:
return self._class_to_dict(wtc_class)
def get_all_classes(self, context, filters=None,
fields=None,
sorts=None, limit=None, marker=None,
page_reverse=False):
marker_obj = self._get_marker_obj(
context, 'wan_tc_class', limit, marker)
all_classes = self._get_collection(context, models.WanTcClass,
self._class_to_dict,
filters=filters, fields=fields,
sorts=sorts, limit=limit,
marker_obj=marker_obj,
page_reverse=page_reverse)
if not filters:
for wtc_class in all_classes:
if wtc_class['id'] == 'root':
all_classes.remove(wtc_class)
break
return all_classes
def _class_to_dict(self, wtc_class, fields=None):
class_dict = {
'id': wtc_class.id,
'direction': wtc_class.direction,
'min': wtc_class.min,
'max': wtc_class.max,
'class_ext_id': wtc_class.class_ext_id,
'parent': wtc_class.parent,
'parent_class_ext_id': wtc_class.parent_class_ext_id
}
return class_dict
def _device_to_dict(self, device, fields=None):
device_dict = {
'id': device.id,
'host': device.host,
'lan_port': device.lan_port,
'wan_port': device.wan_port,
'uptime': device.uptime,
'last_seen': device.heartbeat_timestamp
}
return device_dict
def delete_wan_tc_device(self, context, id):
device = context.session.query(models.WanTcDevice).filter_by(
id=id
).first()
if device:
with context.session.begin(subtransactions=True):
context.session.delete(device)
else:
LOG.error('Trying to delete none existing device. id=%s', id)
def get_device(self, context, id):
device = context.session.query(models.WanTcDevice).filter_by(
id=id
).first()
if device:
return self._device_to_dict(device)
def get_class_tree(self, start_from_id='root'):
context = ctx.get_admin_context()
root_class_db = context.session.query(models.WanTcClass).filter_by(
id=start_from_id).first()
root_class = self._class_to_dict(root_class_db)
self._get_child_classes(context, root_class)
return root_class
def _get_child_classes(self, context, parent_class):
child_classes_db = context.session.query(models.WanTcClass).filter_by(
parent=parent_class['id']).all()
parent_class['child_list'] = []
for child_class_db in child_classes_db:
child_class = self._class_to_dict(child_class_db)
parent_class['child_list'].append(child_class)
self._get_child_classes(context, child_class)
def create_wan_tc_filter(self, context, wan_tc_filter):
wtc_filter_db = models.WanTcFilter(
id=uuidutils.generate_uuid(),
protocol=wan_tc_filter['protocol'],
match=wan_tc_filter['match'],
class_id=wan_tc_filter['class_id']
)
if 'network' in wan_tc_filter:
wtc_filter_db.network = wan_tc_filter['network']
with context.session.begin(subtransactions=True):
context.session.add(wtc_filter_db)
return self._filter_to_dict(wtc_filter_db)
def _filter_to_dict(self, wtc_filter_db, fields=None):
wtc_filter = {
'id': wtc_filter_db.id,
'protocol': wtc_filter_db.protocol,
'match': wtc_filter_db.match,
'class_id': wtc_filter_db.class_id,
'network': wtc_filter_db.network
}
return wtc_filter
def get_wan_tc_filter(self, context, id, fields=None):
wtc_filter_db = context.session.query(models.WanTcFilter).filter_by(
id=id).first()
if wtc_filter_db:
return self._filter_to_dict(wtc_filter_db)
return {}
def get_wan_tc_filters(self, context, filters=None, fields=None,
sorts=None, limit=None, marker=None,
page_reverse=False):
marker_obj = self._get_marker_obj(
context, 'wan_tc_filter', limit, marker)
return self._get_collection(context, models.WanTcFilter,
self._filter_to_dict,
filters=filters, fields=fields,
sorts=sorts, limit=limit,
marker_obj=marker_obj,
page_reverse=page_reverse)
def delete_wan_tc_filter(self, context, id):
filter_db = context.session.query(models.WanTcFilter).filter_by(
id=id
).first()
if filter_db:
with context.session.begin(subtransactions=True):
context.session.delete(filter_db)
else:
LOG.error('Trying to delete none existing tc filter. id=%s', id)
def _get_collection(self, context, model, dict_func, filters=None,
fields=None, sorts=None, limit=None, marker_obj=None,
page_reverse=False):
"""Get collection object based on query for resources."""
if not self._has_attribute(model, filters):
return []
query = self._get_collection_query(context, model, filters=filters,
sorts=sorts,
limit=limit,
marker_obj=marker_obj,
page_reverse=page_reverse)
items = [dict_func(c, fields) for c in query]
if limit and page_reverse:
items.reverse()
return items
def _has_attribute(self, model, filters):
if filters:
for key in filters.keys():
if not hasattr(model, key):
return False
return True
def _get_collection_query(self, context, model, filters=None,
sorts=None, limit=None, marker_obj=None,
page_reverse=False):
"""Get collection query for the models."""
collection = self._model_query(context, model)
collection = self._apply_filters_to_query(collection, model, filters)
return collection
def _get_marker_obj(self, context, resource, limit, marker):
"""Get marker object for the resource."""
if limit and marker:
return getattr(self, '_get_%s' % resource)(context, marker)
return None
def _model_query(self, context, model):
"""Query model based on filter."""
query = context.session.query(model)
query_filter = None
if not context.is_admin and hasattr(model, 'tenant_id'):
query_filter = (model.tenant_id == context.tenant_id)
if query_filter is not None:
query = query.filter(query_filter)
return query
def _apply_filters_to_query(self, query, model, filters):
"""Apply filters to query for the models."""
if filters:
for key, value in filters.items():
column = getattr(model, key, None)
if column:
query = query.filter(column.in_(value))
return query

View File

@ -1,111 +0,0 @@
# Copyright 2017 Huawei corp.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import abc
from neutron.api.v2 import resource_helper
from neutron_lib.api import extensions
from wan_qos.common import constants
RESOURCE_ATTRIBUTE_MAP = {
constants.WAN_TC_PATH: {
'id': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'min': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'is_visible': True,
'default': '',
},
'max': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'is_visible': True,
'default': '',
},
'network': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'is_visible': True,
'default': '',
},
'project_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True,
'is_visible': True}
},
}
class Wantc(extensions.ExtensionDescriptor):
@classmethod
def get_name(cls):
return "WAN Traffic Control single command"
@classmethod
def get_alias(cls):
return "wan-tc"
@classmethod
def get_description(cls):
return "Class for limiting traffic on WAN links using single command"
@classmethod
def get_updated(cls):
return "2017-02-28T00:00:00-00:00"
@classmethod
def get_resources(cls):
"""Returns Ext Resources."""
mem_actions = {}
plural_mappings = resource_helper.build_plural_mappings(
{}, RESOURCE_ATTRIBUTE_MAP)
resources = resource_helper.build_resource_info(plural_mappings,
RESOURCE_ATTRIBUTE_MAP,
constants.WANTC,
action_map=mem_actions,
register_quota=True,
translate_name=True)
return resources
def get_extended_resources(self, version):
if version == "2.0":
return RESOURCE_ATTRIBUTE_MAP
else:
return {}
class WanTcPluginBase(object):
@abc.abstractmethod
def create_wan_tc(self, context, wan_tc):
pass
@abc.abstractmethod
def get_wan_tc(self, context, id, fields=None):
pass
@abc.abstractmethod
def get_wan_tcs(self, context, filters=None, fields=None,
sorts=None, limit=None, marker=None,
page_reverse=False):
pass
@abc.abstractmethod
def update_wan_tc(self, context, id, wan_tc):
pass
@abc.abstractmethod
def delete_wan_tc(self, context, id):
pass

View File

@ -1,114 +0,0 @@
# Copyright 2016 Huawei corp.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import abc
from neutron.api.v2 import resource_helper
from neutron_lib.api import extensions
from wan_qos.common import constants
RESOURCE_ATTRIBUTE_MAP = {
constants.WAN_TC_CLASS_PATH: {
'id': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'parent': {'allow_post': True, 'allow_put': False,
'is_visible': True,
'default': ''},
'direction': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'is_visible': True,
'default': ''
},
'min': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'is_visible': True,
'default': '',
},
'max': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'is_visible': True,
'default': '',
},
'project_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True,
'is_visible': True}
},
}
class Wantcclass(extensions.ExtensionDescriptor):
@classmethod
def get_name(cls):
return "WAN Traffic Control class"
@classmethod
def get_alias(cls):
return "wan-tc-class"
@classmethod
def get_description(cls):
return "Class for limiting traffic on WAN links"
@classmethod
def get_updated(cls):
return "2017-01-16T00:00:00-00:00"
@classmethod
def get_resources(cls):
"""Returns Ext Resources."""
mem_actions = {}
plural_mappings = resource_helper.build_plural_mappings(
{}, RESOURCE_ATTRIBUTE_MAP)
resources = resource_helper.build_resource_info(plural_mappings,
RESOURCE_ATTRIBUTE_MAP,
constants.WANTC,
action_map=mem_actions,
register_quota=True,
translate_name=True)
return resources
def get_extended_resources(self, version):
if version == "2.0":
return RESOURCE_ATTRIBUTE_MAP
else:
return {}
class WanTcClassPluginBase(object):
@abc.abstractmethod
def create_wan_tc_class(self, context, wan_tc_class):
pass
@abc.abstractmethod
def get_wan_tc_class(self, context, id, fields=None):
pass
@abc.abstractmethod
def get_wan_tc_classs(self, context, filters=None, fields=None,
sorts=None, limit=None, marker=None,
page_reverse=False):
pass
@abc.abstractmethod
def update_wan_tc_class(self, context, id, wan_tc_class):
pass
@abc.abstractmethod
def delete_wan_tc_class(self, context, id):
pass

View File

@ -1,99 +0,0 @@
# Copyright 2016 Huawei corp.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import abc
from neutron.api.v2 import resource_helper
from neutron_lib.api import extensions
from wan_qos.common import constants
RESOURCE_ATTRIBUTE_MAP = {
constants.WAN_TC_DEVICE_PATH: {
'id': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'host': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'is_visible': True, 'default': ''},
'lan_port': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'is_visible': True, 'default': ''},
'wan_port': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'is_visible': True},
'uptime': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'is_visible': True},
'last_seen': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'is_visible': True}
},
}
class Wantcdevice(extensions.ExtensionDescriptor):
@classmethod
def get_name(cls):
return "WAN Traffic Control device"
@classmethod
def get_alias(cls):
return "wan-tc-device"
@classmethod
def get_description(cls):
return "Device for limiting traffic on WAN links"
@classmethod
def get_updated(cls):
return "2017-01-15T00:00:00-00:00"
@classmethod
def get_resources(cls):
"""Returns Ext Resources."""
mem_actions = {}
plural_mappings = resource_helper.build_plural_mappings(
{}, RESOURCE_ATTRIBUTE_MAP)
resources = resource_helper.build_resource_info(plural_mappings,
RESOURCE_ATTRIBUTE_MAP,
constants.WANTC,
action_map=mem_actions,
register_quota=True,
translate_name=True)
return resources
def get_extended_resources(self, version):
if version == "2.0":
return RESOURCE_ATTRIBUTE_MAP
else:
return {}
class WanTcDevicePluginBase(object):
@abc.abstractmethod
def get_wan_tc_device(self, context, id, fields=None):
pass
@abc.abstractmethod
def get_wan_tc_devices(self, context, filters=None, fields=None,
sorts=None, limit=None, marker=None,
page_reverse=False):
pass
@abc.abstractmethod
def delete_wan_tc_device(self, context, id):
pass

View File

@ -1,105 +0,0 @@
# Copyright 2016 Huawei corp.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import abc
from neutron.api.v2 import resource_helper
from neutron_lib.api import extensions
from wan_qos.common import constants
RESOURCE_ATTRIBUTE_MAP = {
constants.WAN_TC_FILTER_PATH: {
'id': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'class_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'is_visible': True, 'default': ''},
'protocol': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'is_visible': True, 'default': ''},
'match': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'is_visible': True},
'project_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True,
'is_visible': True}
},
}
class Wantcfilter(extensions.ExtensionDescriptor):
@classmethod
def get_name(cls):
return "WAN Traffic Control filter"
@classmethod
def get_alias(cls):
return "wan-tc-filter"
@classmethod
def get_description(cls):
return "filter to select traffic limit class on WAN links"
@classmethod
def get_updated(cls):
return "2017-01-25T00:00:00-00:00"
@classmethod
def get_resources(cls):
"Returns Ext Resources."
mem_actions = {}
plural_mappings = resource_helper.build_plural_mappings(
{}, RESOURCE_ATTRIBUTE_MAP)
resources = resource_helper.build_resource_info(plural_mappings,
RESOURCE_ATTRIBUTE_MAP,
constants.WANTC,
action_map=mem_actions,
register_quota=True,
translate_name=True)
return resources
def get_extended_resources(self, version):
if version == "2.0":
return RESOURCE_ATTRIBUTE_MAP
else:
return {}
class WanTcFilterPluginBase(object):
@abc.abstractmethod
def create_wan_tc_filter(self, context, wan_tc_filter):
pass
@abc.abstractmethod
def get_wan_tc_filter(self, context, id, fields=None):
pass
@abc.abstractmethod
def get_wan_tc_filters(self, context, filters=None, fields=None,
sorts=None, limit=None, marker=None,
page_reverse=False):
pass
@abc.abstractmethod
def update_wan_tc_filter(self, context, id, wan_tc_filter):
pass
@abc.abstractmethod
def delete_wan_tc_filter(self, context, id):
pass

View File

@ -1,240 +0,0 @@
# Copyright 2016 Huawei corp.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from neutron.common import rpc as n_rpc
from neutron.db import agents_db
from neutron_lib import exceptions
from neutron_lib.plugins import directory
from oslo_config import cfg
from oslo_log import log as logging
import oslo_messaging as messaging
from oslo_utils import importutils
from wan_qos.common import api
from wan_qos.common import constants
from wan_qos.common import topics
from wan_qos.db import wan_qos_db
from wan_qos.extensions import wantc
from wan_qos.extensions import wantcclass
from wan_qos.extensions import wantcdevice
from wan_qos.extensions import wantcfilter
LOG = logging.getLogger(__name__)
class PluginRpcCallback(object):
target = messaging.Target(version='1.0')
def __init__(self, plugin):
super(PluginRpcCallback, self).__init__()
self.plugin = plugin
LOG.debug('rpc callback started.')
def agent_up_notification(self, context, host_info):
LOG.debug('got up notification from %s', host_info['host'])
self.plugin.db.agent_up_notification(context, host_info)
def device_heartbeat(self, context, host):
self.plugin.db.device_heartbeat(context, host)
def get_configuration_from_db(self, context, host):
conf = {
'class_tree': self.plugin.db.get_class_tree(),
'filters': self.plugin.db.get_wan_tc_filters(context)
}
return conf
def get_class_by_id(self, context, id):
return self.plugin.db.get_class_by_id(context, id)
class WanQosPlugin(wantcfilter.WanTcFilterPluginBase,
wantcdevice.WanTcDevicePluginBase,
wantcclass.WanTcClassPluginBase,
wantc.WanTcPluginBase):
supported_extension_aliases = ['wan-tc-filter', 'wan-tc-device',
'wan-tc-class', 'wan-tc']
def __init__(self):
self.db = wan_qos_db.WanTcDb()
rpc_callback = importutils.import_object(
'wan_qos.services.plugin.PluginRpcCallback', self)
endpoints = (
[rpc_callback, agents_db.AgentExtRpcCallback()])
self.agent_rpc = api.TcAgentApi(cfg.CONF.host)
self.conn = n_rpc.create_connection()
self.conn.create_consumer(topics.TC_PLUGIN,
endpoints,
fanout=False)
self.conn.consume_in_threads()
def get_plugin_type(self):
"""Get type of the plugin."""
return constants.WANTC
def get_plugin_description(self):
"""Get description of the plugin."""
return 'Plugin for rate limiting on WAN links.'
@property
def _core_plugin(self):
return directory.get_plugin()
def delete_wan_tc_device(self, context, id):
self.db.delete_wan_tc_device(context, id)
def get_wan_tc_device(self, context, id, fields=None):
return self.db.get_device(context, id)
def get_wan_tc_devices(self, context, filters=None, fields=None,
sorts=None, limit=None, marker=None,
page_reverse=False):
return self.db.get_all_devices(context, filters, fields, sorts, limit,
marker, page_reverse)
def get_wan_tc_class(self, context, id, fields=None):
return self.db.get_class_by_id(context, id)
def update_wan_tc_class(self, context, id, wan_tc_class):
pass
def create_wan_tc_class(self, context, wan_tc_class):
LOG.debug('got new class request: %s', wan_tc_class)
wtc_class_db = self.db.create_wan_tc_class(context,
wan_tc_class[
'wan_tc_class'])
self.agent_rpc.create_wtc_class(context, wtc_class_db)
return wtc_class_db
def delete_wan_tc_class(self, context, id):
LOG.debug('Got request to delete class id: %s', id)
class_tree = self.db.get_class_tree(id)
self.db.delete_wtc_class(context, id)
self.agent_rpc.delete_wtc_class(context, class_tree)
def get_wan_tc_classs(self, context, filters=None, fields=None, sorts=None,
limit=None, marker=None, page_reverse=False):
return self.db.get_all_classes(context, filters, fields, sorts, limit,
marker, page_reverse)
def delete_wan_tc_filter(self, context, id):
wtc_filter = self.get_wan_tc_filter(context, id)
if wtc_filter:
wtc_class = self.get_wan_tc_class(context, wtc_filter['class_id'])
self.db.delete_wan_tc_filter(context, id)
wtc_filter['class'] = wtc_class
self.agent_rpc.delete_wtc_filter(context, wtc_filter)
def get_wan_tc_filters(self, context, filters=None, fields=None,
sorts=None, limit=None, marker=None,
page_reverse=False):
return self.db.get_wan_tc_filters(context, filters, fields, sorts,
limit,
marker, page_reverse)
def create_wan_tc_filter(self, context, wan_tc_filter):
wtc_filter = self.db.create_wan_tc_filter(context,
wan_tc_filter[
'wan_tc_filter'])
# wtc_class = self.get_wan_tc_class(context, wtc_filter['class_id'])
# wtc_filter['class'] = wtc_class
self.agent_rpc.create_wtc_filter(context, wtc_filter)
return wtc_filter
def update_wan_tc_filter(self, context, id, wan_tc_filter):
pass
def get_wan_tc_filter(self, context, id, fields=None):
return self.db.get_wan_tc_filter(context, id, fields)
@staticmethod
def _get_tenant_id_for_create(self, context, resource):
"""Get tenant id for creation of resources."""
if context.is_admin and 'tenant_id' in resource:
tenant_id = resource['tenant_id']
elif (
'tenant_id' in resource and
resource['tenant_id'] != context.tenant_id
):
reason = 'Cannot create resource for another tenant'
raise exceptions.AdminRequired(reason=reason)
else:
tenant_id = context.tenant_id
return tenant_id
def get_wan_tc(self, context, id, fields=None):
filter_db = self.get_wan_tc_filter(context, id, fields)
class_db = self.get_wan_tc_class(context, filter_db['class_id'])
filter_db['min'] = class_db['min']
filter_db['max'] = class_db['max']
return filter_db
def get_wan_tcs(self, context, filters=None, fields=None, sorts=None,
limit=None, marker=None, page_reverse=False):
filters = self.get_wan_tc_filters(context, filters, fields, sorts,
limit, marker, page_reverse)
for filter_db in filters:
class_db = self.get_wan_tc_class(context, filter_db['class_id'])
filter_db['min'] = class_db['min']
filter_db['max'] = class_db['max']
return filters
def create_wan_tc(self, context, wan_tc):
LOG.debug('got WAN_TC: %s', wan_tc)
wan_tc_req = wan_tc['wan_tc']
filter_db = self.get_wan_tc_filters(context, filters={
'network': [wan_tc_req['network']]})
if filter_db:
raise exceptions.InvalidInput(
error_message='Network already has limiter')
network = self._core_plugin.get_network(context, wan_tc_req['network'])
if network['provider:network_type'] != 'vxlan':
raise exceptions.InvalidInput()
vni = network['provider:segmentation_id']
tc_class = {'wan_tc_class': {
'direction': 'both',
'min': wan_tc_req['min']
}
}
if 'max' in wan_tc_req:
tc_class['wan_tc_class']['max'] = wan_tc_req['max']
tc_class_db = self.create_wan_tc_class(context, tc_class)
tc_filter_req = {'wan_tc_filter': {
'protocol': 'vxlan',
'match': 'vni=%s' % vni,
'class_id': tc_class_db['id'],
'network': network['id']
}
}
tc_filter_db = self.create_wan_tc_filter(context, tc_filter_req)
tc_filter_db['min'] = tc_class_db['min']
tc_filter_db['max'] = tc_class_db['max']
return tc_filter_db
def update_wan_tc(self, context, id, wan_tc):
raise exceptions.BadRequest(msg='Not implemented yet!')
def delete_wan_tc(self, context, id):
LOG.debug('Deleting TC: %s', id)
tc_filter = self.get_wan_tc_filter(context, id)
class_id = tc_filter['class_id']
self.delete_wan_tc_filter(context, id)
self.delete_wan_tc_class(context, class_id)

View File

@ -1,34 +0,0 @@
# Copyright 2016 Huawei corp.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import sys
import time
from neutron.agent.common import config
from neutron.common import config as common_config
from wan_qos.services import plugin
def main():
common_config.init(sys.argv[1:])
config.setup_logging()
plugin.WanQosPlugin()
while True:
time.sleep(3)
if __name__ == '__main__':
main()

View File

@ -1,74 +0,0 @@
from neutron.tests.unit import testlib_api
from neutron_lib import context as ctx
from wan_qos.db import wan_qos_db
class TestTcDb(testlib_api.SqlTestCase):
def setUp(self):
super(TestTcDb, self).setUp()
self.db = wan_qos_db.WanTcDb()
self.context = ctx.get_admin_context()
def test_add_class(self):
wtc_class = {
'direction': 'both',
'min': '1mbit'
}
wtc_class_db = self.db.create_wan_tc_class(self.context, wtc_class)
assert wtc_class_db is not None
def test_get_class_by_id(self):
class_db_1 = self._add_class(None, 'both', '1mbit', '2mbit')
class_db_2 = self._add_class(class_db_1['id'], 'both', '2mbit',
'3mbit')
self._add_class(class_db_2['id'], 'both', '3mbit',
'4mbit')
class_by_id = self.db.get_class_by_id(self.context, class_db_1['id'])
# class_by_id = self.db.get_class_by_id(self.context, '111')
print (class_by_id)
def test_get_class_tree(self):
class_db_1 = self._add_class(None, 'both', '1mbit', '2mbit')
class_db_2 = self._add_class(class_db_1['id'], 'both', '2mbit',
'3mbit')
class_db_3 = self._add_class(class_db_2['id'], 'both', '3mbit',
'4mbit')
class_tree = self.db.get_class_tree()
assert class_tree is not None
print (class_tree)
class_tree = self.db.get_class_tree(class_db_1['id'])
assert class_tree is not None
print (class_tree)
class_tree = self.db.get_class_tree(class_db_2['id'])
assert class_tree is not None
print (class_tree)
class_tree = self.db.get_class_tree(class_db_3['id'])
assert class_tree is not None
print (class_tree)
def test_get_classes(self):
self.test_add_class()
all_classes = self.db.get_all_classes(self.context)
print ('all classes: %s' % all_classes)
def _add_class(self, parent, direction, min, max):
wtc_class = {
'direction': direction,
}
if min:
wtc_class['min'] = min
if parent:
wtc_class['parent'] = parent
if max:
wtc_class['max'] = max
return self.db.create_wan_tc_class(self.context, wtc_class)

View File

@ -1,104 +0,0 @@
from neutron.tests.unit import testlib_api
from neutron_lib import context as ctx
from wan_qos.services import plugin
class TestPlugin(testlib_api.SqlTestCase):
def setUp(self):
super(TestPlugin, self).setUp()
self.plugin = plugin.WanQosPlugin()
def test_create_class(self):
wtc_class = {
'wan_tc_class': {
'direction': 'both',
'min': '1mbit'
}
}
wan_tc = self.plugin.create_wan_tc_class(ctx.get_admin_context(),
wtc_class)
assert wan_tc is not None
print (wan_tc)
def test_get_class_by_id(self):
class_db_1 = self._add_class(None, 'both', '1mbit', '2mbit')
class_db_2 = self._add_class(class_db_1['id'], 'both', '2mbit',
'3mbit')
self._add_class(class_db_2['id'], 'both', '3mbit',
'4mbit')
tc_class = self.plugin.get_wan_tc_class(ctx.get_admin_context(),
class_db_1['id'])
print(tc_class)
tc_classes = self.plugin.get_wan_tc_classs(ctx.get_admin_context())
print(tc_classes)
def test_get_all_classes_by_id(self):
class_db_1 = self._add_class(None, 'both', '1mbit', '2mbit')
print ('class_1: %s ' % class_db_1)
filters = {'id': [class_db_1['id']]}
# filters = {'id': ['11']}
# filters = {'name': ['111']}
tc_classes = self.plugin.get_wan_tc_classs(ctx.get_admin_context(),
filters=filters)
print(tc_classes)
filters = {'name': ['111']}
tc_classes = self.plugin.get_wan_tc_classs(ctx.get_admin_context(),
filters=filters)
print(tc_classes)
def test_add_filter(self):
class_db = self._add_class(None, 'both', '1mbit', '2mbit')
filter = self._get_filter(class_db['id'])
filter_db = self.plugin.create_wan_tc_filter(ctx.get_admin_context(),
filter)
print ('filter: %s' % filter_db)
filters = {
'id': [filter_db['id']]
# 'name': ['123']
}
filter_by_id = self.plugin.get_wan_tc_filters(ctx.get_admin_context(),
filters=filters)
print('filter by id: %s' % filter_by_id)
def _get_filter(self, class_id):
filter = {'wan_tc_filter': {
'protocol': 'vxlan',
'match': 'vni=123',
'class_id': class_id
}
}
return filter
def _add_class(self, parent, direction, min, max):
wtc_class = {
'direction': direction,
}
if min:
wtc_class['min'] = min
if parent:
wtc_class['parent'] = parent
if max:
wtc_class['max'] = max
return self.plugin.db.create_wan_tc_class(ctx.get_admin_context(),
wtc_class)

View File

@ -1,145 +0,0 @@
# Copyright (c) 2016 Huawei, 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.tests import base
from oslo_config import cfg
from wan_qos.agent import tc_driver
from wan_qos.services import plugin
WANTC_group = cfg.OptGroup(name='WANTC',
title='WAN QoS options')
opts = [
cfg.StrOpt('lan_port_name',
default='enp1s0f0',
help='LAN side port name'),
cfg.StrOpt('lan_max_rate',
default='100mbit',
help='LAN side port rate'),
cfg.StrOpt('wan_port_name',
default='enp1s0f1',
help='WAN side port name'),
cfg.StrOpt('wan_max_rate',
default='100mbit',
help='WAN side port rate')
]
class TestTcDriver(base.BaseTestCase):
def setUp(self):
super(TestTcDriver, self).setUp()
cfg.CONF.register_group(WANTC_group)
cfg.CONF.register_opts(opts, group='WANTC')
self.tc_agent = tc_driver.TcDriver()
self.tc_agent.set_ports('enp1s0f0', 'enp1s0f1')
def test_clear_all(self):
self.tc_agent.clear_all()
def test_set_root_queue(self):
tc_dict = {
'port_side': 'lan_port',
'max_rate': '100mbit'
}
self.tc_agent.set_root_queue(tc_dict)
tc_dict = {
'port_side': 'wan_port',
'max_rate': '100mbit'
}
self.tc_agent.set_root_queue(tc_dict)
def test_add_limiter(self):
tc_dict = {
'port_side': 'lan_port',
'parent': '1',
'child': '10',
'min': '200kbit',
'max': '512kbit'
}
self.tc_agent.create_traffic_limiter(tc_dict)
tc_dict = {
'port_side': 'wan_port',
'parent': '1',
'child': '10',
'min': '2mbit',
'max': '2mbit'
}
self.tc_agent.create_traffic_limiter(tc_dict)
tc_dict = {
'port_side': 'wan_port',
'parent': '10',
'child': '100',
'min': '200kbit',
'max': '512kbit'
}
self.tc_agent.create_traffic_limiter(tc_dict)
def test_update_limiter(self):
tc_dict = {
'port_side': 'lan_port',
'parent': '1',
'child': '10',
'min': '300kbit',
'max': '400kbit'
}
self.tc_agent.update_traffic_limiter(tc_dict)
tc_dict = {
'port_side': 'wan_port',
'parent': '10',
'child': '100',
'min': '250kbit',
'max': '600kbit'
}
self.tc_agent.update_traffic_limiter(tc_dict)
def test_add_filter(self):
tc_dict = {
'port_side': 'lan_port',
'protocol': 'vxlan',
'vni': 100,
'child': '10'
}
self.tc_agent.create_filter(tc_dict)
tc_dict = {
'port_side': 'wan_port',
'protocol': 'vxlan',
'vni': 100,
'child': '100'
}
self.tc_agent.create_filter(tc_dict)
def test_remove_limiter(self):
tc_dict = {
'port_side': 'lan_port',
'parent': '1',
'child': '10'
}
self.tc_agent.remove_traffic_limiter(tc_dict)
tc_dict = {
'port_side': 'wan_port',
'parent': '1',
'child': '10'
}
self.tc_agent.remove_traffic_limiter(tc_dict)
class TestApiMessages(base.BaseTestCase):
def setUp(self):
super(TestApiMessages, self).setUp()
cfg.CONF.register_group(WANTC_group)
cfg.CONF.register_opts(opts, group='WANTC')
self.plugin = plugin.WanQosPlugin()

View File

@ -1,89 +0,0 @@
# Copyright 2017 Huawei corp.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from neutronclient._i18n import _
from neutronclient.common import exceptions
from neutronclient.common import extension
from wan_qos.common import constants
class WanTc(extension.NeutronClientExtension):
resource = constants.WAN_TC
resource_plural = '%ss' % constants.WAN_TC
path = constants.WAN_TC_PATH
object_path = '/%s' % path
resource_path = '/%s/%%s' % path
versions = ['2.0']
class WanTcShow(extension.ClientExtensionShow, WanTc):
shell_command = 'wan-tc-show'
class WanTcList(extension.ClientExtensionList, WanTc):
shell_command = 'wan-tc-list'
list_columns = ['id', 'network', 'min', 'max']
pagination_support = True
sorting_support = True
class WanTcCreate(extension.ClientExtensionCreate, WanTc):
shell_command = 'wan-tc-create'
def add_known_arguments(self, parser):
parser.add_argument(
'network', metavar='<network>',
help=_('Network ID'))
parser.add_argument(
'--min',
dest='min',
help=_('Set committed rate. (mbit / kbit)'))
parser.add_argument(
'--max',
dest='max',
help=_('Set maximum rate. (mbit / kbit)'))
def args2body(self, parsed_args):
body = {
'network': parsed_args.network
}
if parsed_args.min:
body['min'] = parsed_args.min
else:
raise exceptions.BadRequest('min must be set')
if parsed_args.max:
body['max'] = parsed_args.max
return {self.resource: body}
class WanTcDelete(extension.ClientExtensionDelete, WanTc):
shell_command = 'wan-tc-delete'
class WanTcUpdate(extension.ClientExtensionUpdate, WanTc):
shell_command = 'wan-tc-update'
def add_known_arguments(self, parser):
pass
def args2body(self, parsed_args):
body = {}
return {self.resource: body}

View File

@ -1,98 +0,0 @@
# Copyright 2016 Huawei corp.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from neutronclient._i18n import _
from neutronclient.common import exceptions
from neutronclient.common import extension
from wan_qos.common import constants
class WanTcClass(extension.NeutronClientExtension):
resource = constants.WAN_TC_CLASS
resource_plural = '%ss' % constants.WAN_TC_CLASS
path = constants.WAN_TC_CLASS_PATH
object_path = '/%s' % path
resource_path = '/%s/%%s' % path
versions = ['2.0']
class WanTcClassShow(extension.ClientExtensionShow, WanTcClass):
shell_command = 'wan-tc-class-show'
class WanTcClassList(extension.ClientExtensionList, WanTcClass):
shell_command = 'wan-tc-class-list'
list_columns = ['id', 'parent', 'direction', 'min', 'max']
pagination_support = True
sorting_support = True
class WanTcClassCreate(extension.ClientExtensionCreate, WanTcClass):
shell_command = 'wan-tc-class-create'
def add_known_arguments(self, parser):
parser.add_argument(
'direction', metavar='<DIRECTION>',
choices=['both', 'in', 'out'],
help=_('The direction for the limiter. Can be both/in/out'))
parser.add_argument(
'--min',
dest='min',
help=_('Set committed rate. (mbit / kbit)'))
parser.add_argument(
'--max',
dest='max',
help=_('Set maximum rate. (mbit / kbit)'))
parser.add_argument(
'--parent',
dest='parent',
help=_('Set the parent class of this class. Omit if root.'))
def args2body(self, parsed_args):
body = {
'direction': parsed_args.direction
}
if parsed_args.min:
body['min'] = parsed_args.min
else:
if not parsed_args.max:
raise exceptions.BadRequest('Either min or max must be set')
if parsed_args.max:
body['max'] = parsed_args.max
if parsed_args.parent:
body['parent'] = parsed_args.parent
return {self.resource: body}
class WanTcClassDelete(extension.ClientExtensionDelete, WanTcClass):
shell_command = 'wan-tc-class-delete'
class WanTcClassUpdate(extension.ClientExtensionUpdate, WanTcClass):
shell_command = 'wan-tc-class-update'
def add_known_arguments(self, parser):
pass
def args2body(self, parsed_args):
body = {}
return {self.resource: body}

View File

@ -1,48 +0,0 @@
# Copyright 2016 Huawei corp.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from neutronclient.common import extension
from wan_qos.common import constants
def args2body(self, parsed_args):
body = {constants.WAN_TC_DEVICE: {}, }
return body
class WanTcDevice(extension.NeutronClientExtension):
resource = constants.WAN_TC_DEVICE
resource_plural = '%ss' % constants.WAN_TC_DEVICE
path = constants.WAN_TC_DEVICE_PATH
object_path = '/%s' % path
resource_path = '/%s/%%s' % path
versions = ['2.0']
class WanTcDeviceShow(extension.ClientExtensionShow, WanTcDevice):
shell_command = 'wan-tc-device-show'
class WanTcDeviceList(extension.ClientExtensionList, WanTcDevice):
shell_command = 'wan-tc-device-list'
list_columns = ['id', 'host', 'lan_port', 'wan_port',
'uptime', 'last_seen']
pagination_support = True
sorting_support = True
class WanTcDeviceDelete(extension.ClientExtensionDelete, WanTcDevice):
shell_command = 'wan-tc-device-delete'

View File

@ -1,80 +0,0 @@
# Copyright 2016 Huawei corp.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from neutronclient._i18n import _
from neutronclient.common import extension
from wan_qos.common import constants
class WanTcFilter(extension.NeutronClientExtension):
resource = constants.WAN_TC_FILTER
resource_plural = '%ss' % constants.WAN_TC_FILTER
path = constants.WAN_TC_FILTER_PATH
object_path = '/%s' % path
resource_path = '/%s/%%s' % path
versions = ['2.0']
class WanTcFilterShow(extension.ClientExtensionShow, WanTcFilter):
shell_command = 'wan-tc-filter-show'
class WanTcFilterList(extension.ClientExtensionList, WanTcFilter):
shell_command = 'wan-tc-filter-list'
list_columns = ['id', 'protocol', 'match', 'class_id']
pagination_support = True
sorting_support = True
class WanTcFilterCreate(extension.ClientExtensionCreate, WanTcFilter):
shell_command = 'wan-tc-filter-create'
def add_known_arguments(self, parser):
parser.add_argument(
'protocol', metavar='<protocol>',
choices=['vxlan'],
help=_('Protocol name to select'))
parser.add_argument(
'match', metavar='<MATCH>',
help=_('match fields for protocol name to select'))
parser.add_argument(
'class_id', metavar='<CLASS>',
help=_('Class ID to attach the filter to'))
def args2body(self, parsed_args):
body = {
'protocol': parsed_args.protocol,
'match': parsed_args.match,
'class_id': parsed_args.class_id
}
return {self.resource: body}
class WanTcFilterDelete(extension.ClientExtensionDelete, WanTcFilter):
shell_command = 'wan-tc-filter-delete'
class WanTcFilterUpdate(extension.ClientExtensionUpdate, WanTcFilter):
shell_command = 'wan-tc-filter-update'
def add_known_arguments(self, parser):
pass
def args2body(self, parsed_args):
body = {}
return {self.resource: body}