diff --git a/.zuul.yaml b/.zuul.yaml index 6b9b704..136714d 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -6,8 +6,9 @@ - check-requirements check: jobs: - - tempest-integrated-networking - - neutron-tempest-plugin-dynamic-routing + - neutron-ovs-tempest-dvr + - neutron-tempest-plugin-dynamic-routing: + voting: false gate: jobs: - - tempest-integrated-networking + - neutron-ovs-tempest-dvr diff --git a/doc/source/test-vrrp.rst b/doc/source/test-vrrp.rst index ad6fa00..46cac2d 100644 --- a/doc/source/test-vrrp.rst +++ b/doc/source/test-vrrp.rst @@ -104,7 +104,7 @@ And then run OSKen-VRRP:: Here's the helper executable, os_ken-vrrp:: - #!/usr/bin/env python + #!/usr/bin/env python3 # # Copyright (C) 2013 Nippon Telegraph and Telephone Corporation. # Copyright (C) 2013 Isaku Yamahata diff --git a/os_ken/cmd/manager.py b/os_ken/cmd/manager.py index 34717f1..b2e35f1 100755 --- a/os_ken/cmd/manager.py +++ b/os_ken/cmd/manager.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # # Copyright (C) 2011, 2012 Nippon Telegraph and Telephone Corporation. # Copyright (C) 2011 Isaku Yamahata diff --git a/os_ken/cmd/of_config_cli.py b/os_ken/cmd/of_config_cli.py index 3ce256b..a56d86f 100755 --- a/os_ken/cmd/of_config_cli.py +++ b/os_ken/cmd/of_config_cli.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # # Copyright (C) 2013 Nippon Telegraph and Telephone Corporation. # Copyright (C) 2013 YAMAMOTO Takashi diff --git a/os_ken/cmd/ofa_neutron_agent.py b/os_ken/cmd/ofa_neutron_agent.py index 6b3dfd1..c7ba0f2 100755 --- a/os_ken/cmd/ofa_neutron_agent.py +++ b/os_ken/cmd/ofa_neutron_agent.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (C) 2014 VA Linux Systems Japan K.K. # All Rights Reserved. diff --git a/os_ken/cmd/rpc_cli.py b/os_ken/cmd/rpc_cli.py index da2d401..1737362 100755 --- a/os_ken/cmd/rpc_cli.py +++ b/os_ken/cmd/rpc_cli.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # # Copyright (C) 2013 Nippon Telegraph and Telephone Corporation. # Copyright (C) 2013 YAMAMOTO Takashi diff --git a/os_ken/tests/integrated/common/docker_base.py b/os_ken/tests/integrated/common/docker_base.py index 1e78c8e..0e06e5b 100644 --- a/os_ken/tests/integrated/common/docker_base.py +++ b/os_ken/tests/integrated/common/docker_base.py @@ -140,12 +140,12 @@ def sudo(self, cmd, capture=True, try_times=1, interval=1): class DockerImage(object): - def __init__(self, baseimage='ubuntu:16.04'): + def __init__(self, baseimage='ubuntu:20.04'): self.baseimage = baseimage self.cmd = Command() def get_images(self): - out = self.cmd.sudo('sudo docker images') + out = self.cmd.sudo('docker images') images = [] for line in out.splitlines()[1:]: images.append(line.split()[0]) @@ -171,7 +171,7 @@ def create_quagga(self, tagname='quagga', image=None, check_exist=False): pkges = ' '.join([ 'telnet', 'tcpdump', - 'quagga', + 'quagga-bgpd', ]) if image: use_image = image @@ -181,7 +181,13 @@ def create_quagga(self, tagname='quagga', image=None, check_exist=False): c << 'FROM %s' % use_image c << 'RUN apt-get update' c << 'RUN apt-get install -qy --no-install-recommends %s' % pkges - c << 'CMD /usr/lib/quagga/bgpd' + c << 'RUN echo "#!/bin/sh" > /bgpd' + c << 'RUN echo mkdir -p /run/quagga >> /bgpd' + c << 'RUN echo chmod 755 /run/quagga >> /bgpd' + c << 'RUN echo chown quagga:quagga /run/quagga >> /bgpd' + c << 'RUN echo exec /usr/sbin/bgpd >> /bgpd' + c << 'RUN chmod +x /bgpd' + c << 'CMD /bgpd' self.cmd.sudo('rm -rf %s' % workdir) self.cmd.execute('mkdir -p %s' % workdir) @@ -213,8 +219,8 @@ def create_os_ken(self, tagname='os_ken', image=None, check_exist=False): # might fail if the current directory contains the symlink to # Docker host file systems. '&& rm -rf *.egg-info/ build/ dist/ .tox/ *.log' - '&& pip install -r tools/pip-requires -r tools/optional-requires', - '&& python setup.py install', + '&& pip install -r requirements.txt -r test-requirements.txt', + '&& pip install .', ]) c << install diff --git a/os_ken/tests/integrated/run_tests_with_ovs12.py b/os_ken/tests/integrated/run_tests_with_ovs12.py index b7c7ea3..d5fc12b 100755 --- a/os_ken/tests/integrated/run_tests_with_ovs12.py +++ b/os_ken/tests/integrated/run_tests_with_ovs12.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (C) 2013 Nippon Telegraph and Telephone Corporation. # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/os_ken/tests/integrated/test_of_config.py b/os_ken/tests/integrated/test_of_config.py new file mode 100644 index 0000000..e39d7c9 --- /dev/null +++ b/os_ken/tests/integrated/test_of_config.py @@ -0,0 +1,326 @@ +# Copyright (C) 2013 Nippon Telegraph and Telephone Corporation. +# Copyright (C) 2013 Isaku Yamahata +# +# 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. + +""" +How to run this test + +edit linc config file. LINC-Switch/rel/linc/releases/1.0/sys.config +You can find the sample config I used for the test below + +For this following config to work, the network interface +linc-port and linc-port2 must be created before hand. +(Or edit the port name depending on your environment) +An easy way is to create them as follows +# ip link add linc-port type veth peer name linc-port-peer +# ip link set linc-port up +# ip link add linc-port2 type veth peer name linc-port-peer2 +# ip link set linc-port2 up + +Then run linc +# rel/linc/bin/linc console + +Then run os_ken +# osken-manager --verbose \ + os_ken/tests/integrated/test_of_config.py + + +Here is my sys.config used for this test. +-->8-->8-->8-->8-->8-->8-->8-->8-->8-->8-->8-->8-->8--- +[ + {linc, + [ + {of_config, enabled}, + + {logical_switches, + [ + {switch, 0, + [ + {backend, linc_us4}, + + {controllers, + [ + {"Switch0-DefaultController", "localhost", 6633, tcp} + ]}, + + {ports, + [ + {port, 1, [{interface, "linc-port"}]}, + {port, 2, [{interface, "linc-port2"}]} + ]}, + + {queues_status, disabled}, + + {queues, + [ + ]} + ]} + ]} + ]}, + + {enetconf, + [ + {capabilities, [{base, {1, 1}}, + {startup, {1, 0}}, + {'writable-running', {1, 0}}]}, + {callback_module, linc_ofconfig}, + {sshd_ip, any}, + {sshd_port, 1830}, + {sshd_user_passwords, + [ + {"linc", "linc"} + ]} + ]}, + + {lager, + [ + {handlers, + [ + {lager_console_backend, info}, + {lager_file_backend, + [ + {"log/error.log", error, 10485760, "$D0", 5}, + {"log/console.log", info, 10485760, "$D0", 5} + ]} + ]} + ]}, + + {sasl, + [ + {sasl_error_logger, {file, "log/sasl-error.log"}}, + {errlog_type, error}, + {error_logger_mf_dir, "log/sasl"}, % Log directory + {error_logger_mf_maxbytes, 10485760}, % 10 MB max file size + {error_logger_mf_maxfiles, 5} % 5 files max + ]} +]. +-->8-->8-->8-->8-->8-->8-->8-->8-->8-->8-->8-->8-->8-- + +""" + +import traceback + +import lxml.etree +import ncclient + +from os_ken.base import app_manager +from os_ken.lib.netconf import constants as nc_consts +from os_ken.lib import hub +from os_ken.lib import of_config +from os_ken.lib.of_config import capable_switch +from os_ken.lib.of_config import constants as ofc_consts + + +# Change those depending on switch configuration +HOST = '127.0.0.1' +PORT = 1830 +USERNAME = 'linc' +PASSWORD = 'linc' + +CAPABLE_SWITCH_ID = 'CapableSwitch0' +LOGICAL_SWITCH = 'LogicalSwitch0' +PORT_ID = 'LogicalSwitch0-Port2' +CONTROLLER_ID = 'Switch0-DefaultController' + +PORT_DICT = { + 'capable_switch': CAPABLE_SWITCH_ID, + 'port_id': PORT_ID, + 'logical_switch': LOGICAL_SWITCH, + 'controller_id': CONTROLLER_ID, + 'ip': HOST, +} + +SWITCH_PORT_DOWN = ''' + + + %(capable_switch)s + + + %(port_id)s + + down + false + false + false + + + + + +''' % PORT_DICT + +SWITCH_ADVERTISED = ''' + + + %(capable_switch)s + + + %(port_id)s + + + 10Mb-FD + true + copper + unsupported + + + + + + +''' % PORT_DICT + +SWITCH_CONTROLLER = ''' + + + %(capable_switch)s + + + %(logical_switch)s + + + %(controller_id)s + master + %(ip)s + 6633 + tcp + + + + + + +''' % PORT_DICT + + +def _get_schema(): + # file_name = of_config.OF_CONFIG_1_0_XSD + # file_name = of_config.OF_CONFIG_1_1_XSD + file_name = of_config.OF_CONFIG_1_1_1_XSD + return lxml.etree.XMLSchema(file=file_name) + + +class OFConfigClient(app_manager.OSKenApp): + def __init__(self, *args, **kwargs): + super(OFConfigClient, self).__init__(*args, **kwargs) + self.switch = capable_switch.OFCapableSwitch( + host=HOST, port=PORT, username=USERNAME, password=PASSWORD, + unknown_host_cb=lambda host, fingeprint: True) + hub.spawn(self._do_of_config) + + def _validate(self, tree): + xmlschema = _get_schema() + try: + xmlschema.assertValid(tree) + except: + traceback.print_exc() + + def _do_get(self): + data_xml = self.switch.raw_get() + + tree = lxml.etree.fromstring(data_xml) + # print(lxml.etree.tostring(tree, pretty_print=True)) + self._validate(tree) + + name_spaces = set() + for e in tree.iter(): + name_spaces.add(capable_switch.get_ns_tag(e.tag)[0]) + print(name_spaces) + + return tree + + def _do_get_config(self, source): + print('source = %s' % source) + config_xml = self.switch.raw_get_config(source) + + tree = lxml.etree.fromstring(config_xml) + # print(lxml.etree.tostring(tree, pretty_print=True)) + self._validate(tree) + + def _do_edit_config(self, config): + tree = lxml.etree.fromstring(config) + self._validate(tree) + self.switch.raw_edit_config(target='running', config=config) + + def _print_ports(self, tree, ns): + for port in tree.findall('{%s}%s/{%s}%s' % (ns, ofc_consts.RESOURCES, + ns, ofc_consts.PORT)): + print(lxml.etree.tostring(port, pretty_print=True)) + + def _set_ports_down(self): + """try to set all ports down with etree operation""" + tree = self._do_get() + print(lxml.etree.tostring(tree, pretty_print=True)) + + qname = lxml.etree.QName(tree.tag) + ns = qname.namespace + self._print_ports(tree, ns) + + switch_id = tree.find('{%s}%s' % (ns, ofc_consts.ID)) + resources = tree.find('{%s}%s' % (ns, ofc_consts.RESOURCES)) + configuration = tree.find( + '{%s}%s/{%s}%s/{%s}%s' % (ns, ofc_consts.RESOURCES, + ns, ofc_consts.PORT, + ns, ofc_consts.CONFIGURATION)) + admin_state = tree.find( + '{%s}%s/{%s}%s/{%s}%s/{%s}%s' % (ns, ofc_consts.RESOURCES, + ns, ofc_consts.PORT, + ns, ofc_consts.CONFIGURATION, + ns, ofc_consts.ADMIN_STATE)) + + config_ = lxml.etree.Element( + '{%s}%s' % (ncclient.xml_.BASE_NS_1_0, nc_consts.CONFIG)) + capable_switch_ = lxml.etree.SubElement(config_, tree.tag) + switch_id_ = lxml.etree.SubElement(capable_switch_, switch_id.tag) + switch_id_.text = switch_id.text + resources_ = lxml.etree.SubElement(capable_switch_, + resources.tag) + for port in tree.findall( + '{%s}%s/{%s}%s' % (ns, ofc_consts.RESOURCES, + ns, ofc_consts.PORT)): + resource_id = port.find('{%s}%s' % (ns, ofc_consts.RESOURCE_ID)) + + port_ = lxml.etree.SubElement(resources_, port.tag) + resource_id_ = lxml.etree.SubElement(port_, resource_id.tag) + resource_id_.text = resource_id.text + configuration_ = lxml.etree.SubElement(port_, configuration.tag) + configuration_.set(ofc_consts.OPERATION, nc_consts.MERGE) + admin_state_ = lxml.etree.SubElement(configuration_, + admin_state.tag) + admin_state_.text = ofc_consts.DOWN + self._do_edit_config(lxml.etree.tostring(config_, pretty_print=True)) + + tree = self._do_get() + self._print_ports(tree, ns) + + def _do_of_config(self): + self._do_get() + self._do_get_config('running') + self._do_get_config('startup') + + # LINC doesn't support 'candidate' datastore + try: + self._do_get_config('candidate') + except ncclient.NCClientError: + traceback.print_exc() + + # use raw XML format + self._do_edit_config(SWITCH_PORT_DOWN) + self._do_edit_config(SWITCH_ADVERTISED) + self._do_edit_config(SWITCH_CONTROLLER) + + self._set_ports_down() + + self.switch.close_session() diff --git a/os_ken/tests/packet_data_generator3/gen.py b/os_ken/tests/packet_data_generator3/gen.py index c44666d..00ca928 100644 --- a/os_ken/tests/packet_data_generator3/gen.py +++ b/os_ken/tests/packet_data_generator3/gen.py @@ -1,4 +1,4 @@ -#! /usr/bin/env python +#! /usr/bin/env python3 import getopt import os diff --git a/os_ken/tests/switch/run_mininet.py b/os_ken/tests/switch/run_mininet.py index 8ad5895..6038dde 100755 --- a/os_ken/tests/switch/run_mininet.py +++ b/os_ken/tests/switch/run_mininet.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import sys diff --git a/os_ken/tests/switch/tester.py b/os_ken/tests/switch/tester.py index e39513b..62b88a1 100644 --- a/os_ken/tests/switch/tester.py +++ b/os_ken/tests/switch/tester.py @@ -56,7 +56,7 @@ ('os_ken.lib.packet.ospf', 'StringifyMixin'): '' } -for modname, moddef in sys.modules.items(): +for modname, moddef in sys.modules.copy().items(): if not modname.startswith(PKT_LIB_PATH) or not moddef: continue for (clsname, clsdef, ) in inspect.getmembers(moddef): diff --git a/os_ken/tests/unit/cmd/test_manager.py b/os_ken/tests/unit/cmd/test_manager.py index 7cd322c..22730c1 100644 --- a/os_ken/tests/unit/cmd/test_manager.py +++ b/os_ken/tests/unit/cmd/test_manager.py @@ -17,7 +17,7 @@ import unittest from unittest import mock -from imp import reload +from importlib import reload from os_ken.cmd.manager import main @@ -39,6 +39,10 @@ def tearDown(self): def test_version(self): self.assertRaises(SystemExit, main) + @mock.patch('sys.argv', new=['osken-manager', '--help']) + def test_help(self): + self.assertRaises(SystemExit, main) + @staticmethod def _reset_globals(): # hack to reset globals like SERVICE_BRICKS. diff --git a/os_ken/tests/unit/ofproto/test_ofproto.py b/os_ken/tests/unit/ofproto/test_ofproto.py index 6e92da6..d3e787a 100644 --- a/os_ken/tests/unit/ofproto/test_ofproto.py +++ b/os_ken/tests/unit/ofproto/test_ofproto.py @@ -16,7 +16,7 @@ # vim: tabstop=4 shiftwidth=4 softtabstop=4 -from imp import reload +from importlib import reload import unittest import logging diff --git a/releasenotes/notes/update-quagga-ebdaa99f7de660d7.yaml b/releasenotes/notes/update-quagga-ebdaa99f7de660d7.yaml new file mode 100644 index 0000000..0f38a13 --- /dev/null +++ b/releasenotes/notes/update-quagga-ebdaa99f7de660d7.yaml @@ -0,0 +1,13 @@ +--- +upgrade: + - | + The default docker base image used in testing has been updated to + ``ubuntu:20.04``. You may need to update your testing code + accordingly. +fixes: + - | + The quagga container used for testing neutron-dynamic-routing was + failing to start due to permission issues. A startup script has + been added to dynamically set the correct permissions. + See bug + `2031526 `_. diff --git a/releasenotes/source/2023.1.rst b/releasenotes/source/2023.1.rst new file mode 100644 index 0000000..d123847 --- /dev/null +++ b/releasenotes/source/2023.1.rst @@ -0,0 +1,6 @@ +=========================== +2023.1 Series Release Notes +=========================== + +.. release-notes:: + :branch: stable/2023.1 diff --git a/releasenotes/source/2023.2.rst b/releasenotes/source/2023.2.rst new file mode 100644 index 0000000..a4838d7 --- /dev/null +++ b/releasenotes/source/2023.2.rst @@ -0,0 +1,6 @@ +=========================== +2023.2 Series Release Notes +=========================== + +.. release-notes:: + :branch: stable/2023.2 diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst index 76adeb5..e07da89 100644 --- a/releasenotes/source/index.rst +++ b/releasenotes/source/index.rst @@ -6,6 +6,8 @@ :maxdepth: 1 unreleased + 2023.2 + 2023.1 zed yoga xena diff --git a/releasenotes/source/yoga.rst b/releasenotes/source/yoga.rst index 7cd5e90..43cafde 100644 --- a/releasenotes/source/yoga.rst +++ b/releasenotes/source/yoga.rst @@ -3,4 +3,4 @@ Yoga Series Release Notes ========================= .. release-notes:: - :branch: stable/yoga + :branch: unmaintained/yoga diff --git a/setup.cfg b/setup.cfg index 9e4433c..35bab6f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -17,6 +17,7 @@ classifier = Programming Language :: Python :: 3 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 [files] packages = diff --git a/setup.py b/setup.py index 056c16c..c1ece58 100644 --- a/setup.py +++ b/setup.py @@ -13,16 +13,8 @@ # 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'], diff --git a/tools/doc-requires b/tools/doc-requires deleted file mode 100644 index 6b104fb..0000000 --- a/tools/doc-requires +++ /dev/null @@ -1,2 +0,0 @@ -Sphinx -sphinx-rtd-theme diff --git a/tools/normalize_json.py b/tools/normalize_json.py index 2d9cbb1..bb15567 100755 --- a/tools/normalize_json.py +++ b/tools/normalize_json.py @@ -1,4 +1,4 @@ -#! /usr/bin/env python +#! /usr/bin/env python3 # Copyright (C) 2013 Nippon Telegraph and Telephone Corporation. # Copyright (C) 2013 YAMAMOTO Takashi diff --git a/tools/optional-requires b/tools/optional-requires deleted file mode 100644 index 1bc4cce..0000000 --- a/tools/optional-requires +++ /dev/null @@ -1,5 +0,0 @@ -lxml!=3.7.0,>=2.3 # OF-Config -ncclient # OF-Config -cryptography!=1.5.2 # Required by paramiko -paramiko # NETCONF, BGP speaker (SSH console) -SQLAlchemy>=1.0.10,<1.1.0 # Zebra protocol service diff --git a/tools/pip-requires b/tools/pip-requires deleted file mode 100644 index 16d105d..0000000 --- a/tools/pip-requires +++ /dev/null @@ -1,7 +0,0 @@ -eventlet>=0.26.1 -msgpack>=1.0.0 # RPC library, BGP speaker(net_cntl) -netaddr>=0.7.18 -oslo.config>=5.1.0 -ovs>=2.8.0 # OVSDB -Routes>=2.3.1 # wsgi -WebOb>=1.8.2 # wsgi diff --git a/tools/topology_graphviz.py b/tools/topology_graphviz.py index e7884fc..447e21a 100755 --- a/tools/topology_graphviz.py +++ b/tools/topology_graphviz.py @@ -1,4 +1,4 @@ -#! /usr/bin/env python +#! /usr/bin/env python3 # Copyright (C) 2013 Nippon Telegraph and Telephone Corporation. # Copyright (C) 2013 YAMAMOTO Takashi diff --git a/tox.ini b/tox.ini index 8abc5d5..b545da4 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,6 @@ [tox] minversion = 3.18.0 envlist = py3,pep8 -skipsdist = True ignore_basepython_conflict = True [testenv] @@ -40,10 +39,10 @@ commands = deps = -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} -r{toxinidir}/doc/requirements.txt + -r{toxinidir}/requirements.txt commands = sphinx-build -W -b html doc/source doc/build/html [testenv:pdf-docs] -envdir = {toxworkdir}/docs deps = {[testenv:docs]deps} allowlist_externals = make