Retire repo
This repository was never used, retire it. Depends-On: https://review.opendev.org/673543 Change-Id: I40d5e939bb0daca094fce64f0662018188b5984e
This commit is contained in:
parent
1ab6c6a3a0
commit
8fb398dc08
17
.gitignore
vendored
17
.gitignore
vendored
@ -1,17 +0,0 @@
|
||||
# Python
|
||||
*.pyc
|
||||
|
||||
# Packages
|
||||
.eggs
|
||||
*.egg-info
|
||||
build/
|
||||
dist/
|
||||
|
||||
# Testing
|
||||
.tox
|
||||
.testrepository
|
||||
|
||||
# Editors
|
||||
*~
|
||||
.*.swp
|
||||
.*sw?
|
@ -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
|
10
README.rst
10
README.rst
@ -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.
|
@ -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
|
||||
|
39
setup.cfg
39
setup.cfg
@ -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
|
27
setup.py
27
setup.py
@ -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)
|
@ -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
|
@ -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
51
tox.ini
@ -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
|
@ -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"
|
@ -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()
|
@ -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)
|
@ -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)
|
@ -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()
|
@ -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)
|
@ -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'
|
@ -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'
|
@ -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()
|
@ -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"}
|
@ -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())
|
||||
)
|
@ -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))
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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)
|
@ -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()
|
@ -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)
|
@ -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)
|
@ -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()
|
@ -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}
|
@ -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}
|
@ -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'
|
@ -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}
|
Loading…
Reference in New Issue
Block a user