summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBence Romsics <bence.romsics@gmail.com>2022-12-28 15:58:17 +0100
committerBence Romsics <bence.romsics@gmail.com>2023-05-09 11:49:17 +0200
commit0390ada97c01031e675caf43b5028bb311331865 (patch)
treee00d303bc1871a342d60487904029b5b832353e4
parent0b954831060089588fb17367c0c1553d6b230d67 (diff)
downloadneutron-0390ada97c01031e675caf43b5028bb311331865.tar.gz
port-hints: api extension
api extension db model db migration ovo (including changes affecting push rpc) extension driver policies To enable this: * neutron-db-manage upgrade 6f1145bff34c * ml2_conf.ini: [ml2] extension_drivers += port_hints This patch also bumps neutron-lib requirement to 3.5.0. Change-Id: I80816618285d742775bc0534510c0f874f84ed2e Partial-Bug: #1990842 Related-Change (spec): https://review.opendev.org/c/openstack/neutron-specs/+/862133 Related-Change (n-lib api-def): https://review.opendev.org/c/openstack/neutron-lib/+/870080
-rw-r--r--neutron/conf/policies/port.py23
-rw-r--r--neutron/db/migration/alembic_migrations/versions/2023.2/expand/6f1145bff34c_port_hints.py45
-rw-r--r--neutron/db/migration/alembic_migrations/versions/EXPAND_HEAD2
-rw-r--r--neutron/db/models/port_hints.py35
-rw-r--r--neutron/db/port_hints_db.py53
-rw-r--r--neutron/extensions/port_hints.py20
-rw-r--r--neutron/objects/port/extensions/port_hints.py53
-rw-r--r--neutron/objects/ports.py9
-rw-r--r--neutron/plugins/ml2/extensions/port_hints.py45
-rw-r--r--neutron/tests/unit/conf/policies/test_port.py60
-rw-r--r--neutron/tests/unit/db/test_db_base_plugin_v2.py2
-rw-r--r--neutron/tests/unit/extensions/test_port_hints.py85
-rw-r--r--neutron/tests/unit/objects/port/extensions/test_port_hints.py33
-rw-r--r--neutron/tests/unit/objects/test_objects.py3
-rw-r--r--neutron/tests/unit/objects/test_ports.py6
-rw-r--r--requirements.txt2
-rw-r--r--setup.cfg1
17 files changed, 472 insertions, 5 deletions
diff --git a/neutron/conf/policies/port.py b/neutron/conf/policies/port.py
index 5783f080bb..bce04da941 100644
--- a/neutron/conf/policies/port.py
+++ b/neutron/conf/policies/port.py
@@ -270,6 +270,15 @@ rules = [
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY)
),
+ policy.DocumentedRuleDefault(
+ name='create_port:hints',
+ check_str=base.ADMIN,
+ scope_types=['project'],
+ description=(
+ 'Specify ``hints`` attribute when creating a port'
+ ),
+ operations=ACTION_POST,
+ ),
policy.DocumentedRuleDefault(
name='get_port',
@@ -350,6 +359,13 @@ rules = [
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY)
),
+ policy.DocumentedRuleDefault(
+ name='get_port:hints',
+ check_str=base.ADMIN,
+ scope_types=['project'],
+ description='Get ``hints`` attribute of a port',
+ operations=ACTION_GET,
+ ),
# TODO(amotoki): Add get_port:binding:vnic_type
# TODO(amotoki): Add get_port:binding:data_plane_status
@@ -592,6 +608,13 @@ rules = [
deprecated_reason=DEPRECATED_REASON,
deprecated_since=versionutils.deprecated.WALLABY)
),
+ policy.DocumentedRuleDefault(
+ name='update_port:hints',
+ check_str=base.ADMIN,
+ scope_types=['project'],
+ description='Update ``hints`` attribute of a port',
+ operations=ACTION_PUT,
+ ),
policy.DocumentedRuleDefault(
name='delete_port',
diff --git a/neutron/db/migration/alembic_migrations/versions/2023.2/expand/6f1145bff34c_port_hints.py b/neutron/db/migration/alembic_migrations/versions/2023.2/expand/6f1145bff34c_port_hints.py
new file mode 100644
index 0000000000..b82d3de956
--- /dev/null
+++ b/neutron/db/migration/alembic_migrations/versions/2023.2/expand/6f1145bff34c_port_hints.py
@@ -0,0 +1,45 @@
+# Copyright 2023 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 alembic import op
+from neutron_lib.db import constants as db_const
+import sqlalchemy as sa
+
+
+"""port_hints
+
+Revision ID: 6f1145bff34c
+Revises: 93f394357a27
+Create Date: 2023-01-01 00:00:00.000000
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '6f1145bff34c'
+down_revision = '93f394357a27'
+
+
+def upgrade():
+ op.create_table(
+ 'porthints',
+ sa.Column(
+ 'port_id',
+ sa.String(length=db_const.UUID_FIELD_SIZE),
+ sa.ForeignKey('ports.id', ondelete='CASCADE'),
+ primary_key=True),
+ sa.Column('hints',
+ sa.String(4095),
+ nullable=False),
+ )
diff --git a/neutron/db/migration/alembic_migrations/versions/EXPAND_HEAD b/neutron/db/migration/alembic_migrations/versions/EXPAND_HEAD
index 88323e719e..8e31a8bd56 100644
--- a/neutron/db/migration/alembic_migrations/versions/EXPAND_HEAD
+++ b/neutron/db/migration/alembic_migrations/versions/EXPAND_HEAD
@@ -1 +1 @@
-93f394357a27
+6f1145bff34c
diff --git a/neutron/db/models/port_hints.py b/neutron/db/models/port_hints.py
new file mode 100644
index 0000000000..8ef171bba5
--- /dev/null
+++ b/neutron/db/models/port_hints.py
@@ -0,0 +1,35 @@
+# Copyright 2023 Ericsson Software Technology
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from neutron_lib.db import constants as db_const
+from neutron_lib.db import model_base
+import sqlalchemy as sa
+
+from neutron.db import models_v2
+
+
+class PortHints(model_base.BASEV2):
+ __tablename__ = 'porthints'
+ port_id = sa.Column(
+ sa.String(db_const.UUID_FIELD_SIZE),
+ sa.ForeignKey('ports.id', ondelete='CASCADE'),
+ primary_key=True)
+ hints = sa.Column('hints', sa.String(length=4095), nullable=False)
+ port = sa.orm.relationship(
+ models_v2.Port,
+ load_on_pending=True,
+ backref=sa.orm.backref(
+ 'hints', uselist=False, cascade='delete', lazy='subquery'))
+
+ revises_on_change = ('port', )
diff --git a/neutron/db/port_hints_db.py b/neutron/db/port_hints_db.py
new file mode 100644
index 0000000000..0b45b413fb
--- /dev/null
+++ b/neutron/db/port_hints_db.py
@@ -0,0 +1,53 @@
+# Copyright 2023 Ericsson Software Technology
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from neutron_lib.api.definitions import port_hints as phints_def
+from oslo_serialization import jsonutils
+
+from neutron.objects.port.extensions import port_hints as phints_obj
+
+
+class PortHintsMixin(object):
+ """Mixin class to add hints to a port"""
+
+ def _process_create_port(self, context, data, result):
+ if not data.get(phints_def.HINTS):
+ result[phints_def.HINTS] = None
+ return
+
+ obj = phints_obj.PortHints(
+ context, port_id=result['id'],
+ hints=data[phints_def.HINTS])
+ obj.create()
+ result[phints_def.HINTS] = data[phints_def.HINTS]
+
+ def _process_update_port(self, context, data, result):
+ obj = phints_obj.PortHints.get_object(
+ context, port_id=result['id'])
+
+ if obj:
+ if data[phints_def.HINTS]:
+ obj.hints = data[phints_def.HINTS]
+ obj.update()
+ else:
+ obj.delete()
+ result[phints_def.HINTS] = data[phints_def.HINTS]
+ else:
+ self._process_create_port(context, data, result)
+
+ def _extend_port_dict(self, port_db, result):
+ if port_db.hints:
+ result[phints_def.HINTS] = jsonutils.loads(port_db.hints.hints)
+ else:
+ result[phints_def.HINTS] = None
diff --git a/neutron/extensions/port_hints.py b/neutron/extensions/port_hints.py
new file mode 100644
index 0000000000..74e9e6007c
--- /dev/null
+++ b/neutron/extensions/port_hints.py
@@ -0,0 +1,20 @@
+# Copyright 2023 Ericsson Software Technology
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from neutron_lib.api.definitions import port_hints as phints_def
+from neutron_lib.api import extensions as api_extensions
+
+
+class Port_hints(api_extensions.APIExtensionDescriptor):
+ api_definition = phints_def
diff --git a/neutron/objects/port/extensions/port_hints.py b/neutron/objects/port/extensions/port_hints.py
new file mode 100644
index 0000000000..a9fd1c793f
--- /dev/null
+++ b/neutron/objects/port/extensions/port_hints.py
@@ -0,0 +1,53 @@
+# Copyright 2023 Ericsson Software Technology
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from neutron_lib.objects import common_types
+
+from neutron.db.models import port_hints
+from neutron.objects import base
+
+
+@base.NeutronObjectRegistry.register
+class PortHints(base.NeutronDbObject):
+ # Version 1.0: Initial version
+ VERSION = '1.0'
+
+ db_model = port_hints.PortHints
+
+ primary_keys = ['port_id']
+
+ fields = {
+ 'port_id': common_types.UUIDField(),
+ 'hints': common_types.DictOfMiscValuesField(),
+ }
+
+ foreign_keys = {'Port': {'port_id': 'id'}}
+
+ @classmethod
+ def modify_fields_to_db(cls, fields):
+ result = super(PortHints, cls).modify_fields_to_db(fields)
+ if 'hints' in result:
+ # dump field into string, set '' if empty '{}' or None
+ result['hints'] = (
+ cls.filter_to_json_str(result['hints'], default=''))
+ return result
+
+ @classmethod
+ def modify_fields_from_db(cls, db_obj):
+ fields = super(PortHints, cls).modify_fields_from_db(db_obj)
+ if 'hints' in fields:
+ # load string from DB into dict, set None if hints is ''
+ fields['hints'] = (
+ cls.load_json_from_str(fields['hints']))
+ return fields
diff --git a/neutron/objects/ports.py b/neutron/objects/ports.py
index 462d86944c..e9fd61b38e 100644
--- a/neutron/objects/ports.py
+++ b/neutron/objects/ports.py
@@ -336,7 +336,8 @@ class Port(base.NeutronDbObject):
# Version 1.5: Added qos_network_policy_id field
# Version 1.6: Added numa_affinity_policy field
# Version 1.7: Added port_device field
- VERSION = '1.7'
+ # Version 1.8: Added hints field
+ VERSION = '1.8'
db_model = models_v2.Port
@@ -370,6 +371,9 @@ class Port(base.NeutronDbObject):
'fixed_ips': obj_fields.ListOfObjectsField(
'IPAllocation', nullable=True
),
+ 'hints': obj_fields.ObjectField(
+ 'PortHints', nullable=True
+ ),
# TODO(ihrachys): consider converting to boolean
'security': obj_fields.ObjectField(
'PortSecurity', nullable=True
@@ -407,6 +411,7 @@ class Port(base.NeutronDbObject):
'distributed_bindings',
'dns',
'fixed_ips',
+ 'hints',
'numa_affinity_policy',
'qos_policy_id',
'qos_network_policy_id',
@@ -610,6 +615,8 @@ class Port(base.NeutronDbObject):
primitive.pop('numa_affinity_policy', None)
if _target_version < (1, 7):
primitive.pop('device_profile', None)
+ if _target_version < (1, 8):
+ primitive.pop('hints', None)
@classmethod
@db_api.CONTEXT_READER
diff --git a/neutron/plugins/ml2/extensions/port_hints.py b/neutron/plugins/ml2/extensions/port_hints.py
new file mode 100644
index 0000000000..1e4ba654f4
--- /dev/null
+++ b/neutron/plugins/ml2/extensions/port_hints.py
@@ -0,0 +1,45 @@
+# Copyright 2023 Ericsson Software Technology
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from neutron_lib.api.definitions import port_hints as phints_def
+from neutron_lib.plugins.ml2 import api
+from oslo_log import log as logging
+
+from neutron.db import port_hints_db
+
+
+LOG = logging.getLogger(__name__)
+
+
+class PortHintsExtensionDriver(
+ api.ExtensionDriver, port_hints_db.PortHintsMixin):
+
+ _supported_extension_alias = phints_def.ALIAS
+
+ def initialize(self):
+ LOG.info('PortHintsExtensionDriver initialization complete')
+
+ @property
+ def extension_alias(self):
+ return self._supported_extension_alias
+
+ def process_create_port(self, context, data, result):
+ self._process_create_port(context, data, result)
+
+ def process_update_port(self, context, data, result):
+ if phints_def.HINTS in data:
+ self._process_update_port(context, data, result)
+
+ def extend_port_dict(self, session, port_db, result):
+ self._extend_port_dict(port_db, result)
diff --git a/neutron/tests/unit/conf/policies/test_port.py b/neutron/tests/unit/conf/policies/test_port.py
index c50d3feb10..8248960abb 100644
--- a/neutron/tests/unit/conf/policies/test_port.py
+++ b/neutron/tests/unit/conf/policies/test_port.py
@@ -532,6 +532,16 @@ class AdminTests(PortAPITestCase):
'create_port:allowed_address_pairs:ip_address',
self.alt_target))
+ def test_create_port_with_hints(self):
+ self.assertTrue(
+ policy.enforce(self.context,
+ 'create_port:hints',
+ self.target))
+ self.assertTrue(
+ policy.enforce(self.context,
+ 'create_port:hints',
+ self.alt_target))
+
def test_get_port(self):
self.assertTrue(
policy.enforce(self.context, 'get_port', self.target))
@@ -578,6 +588,14 @@ class AdminTests(PortAPITestCase):
policy.enforce(
self.context, 'get_port:resource_request', self.alt_target))
+ def test_get_port_hints(self):
+ self.assertTrue(
+ policy.enforce(
+ self.context, 'get_port:hints', self.target))
+ self.assertTrue(
+ policy.enforce(
+ self.context, 'get_port:hints', self.alt_target))
+
def test_update_port(self):
self.assertTrue(
policy.enforce(self.context, 'update_port', self.target))
@@ -701,6 +719,16 @@ class AdminTests(PortAPITestCase):
'update_port:data_plane_status',
self.alt_target))
+ def test_update_port_hints(self):
+ self.assertTrue(
+ policy.enforce(self.context,
+ 'update_port:hints',
+ self.target))
+ self.assertTrue(
+ policy.enforce(self.context,
+ 'update_port:hints',
+ self.alt_target))
+
def test_delete_port(self):
self.assertTrue(
policy.enforce(self.context, 'delete_port', self.target))
@@ -850,6 +878,18 @@ class ProjectMemberTests(AdminTests):
self.context, 'create_port:allowed_address_pairs:ip_address',
self.alt_target)
+ def test_create_port_with_hints(self):
+ self.assertRaises(
+ base_policy.PolicyNotAuthorized,
+ policy.enforce,
+ self.context, 'create_port:hints',
+ self.target)
+ self.assertRaises(
+ base_policy.PolicyNotAuthorized,
+ policy.enforce,
+ self.context, 'create_port:hints',
+ self.alt_target)
+
def test_get_port(self):
self.assertTrue(
policy.enforce(self.context, 'get_port', self.target))
@@ -907,6 +947,16 @@ class ProjectMemberTests(AdminTests):
policy.enforce, self.context, 'get_port:resource_request',
self.alt_target)
+ def test_get_port_hints(self):
+ self.assertRaises(
+ base_policy.PolicyNotAuthorized,
+ policy.enforce, self.context, 'get_port:hints',
+ self.target)
+ self.assertRaises(
+ base_policy.PolicyNotAuthorized,
+ policy.enforce, self.context, 'get_port:hints',
+ self.alt_target)
+
def test_update_port(self):
self.assertTrue(
policy.enforce(self.context, 'update_port', self.target))
@@ -1053,6 +1103,16 @@ class ProjectMemberTests(AdminTests):
policy.enforce,
self.context, 'update_port:data_plane_status', self.alt_target)
+ def test_update_port_hints(self):
+ self.assertRaises(
+ base_policy.PolicyNotAuthorized,
+ policy.enforce,
+ self.context, 'update_port:hints', self.target)
+ self.assertRaises(
+ base_policy.PolicyNotAuthorized,
+ policy.enforce,
+ self.context, 'update_port:hints', self.alt_target)
+
def test_delete_port(self):
self.assertTrue(
policy.enforce(self.context, 'delete_port', self.target))
diff --git a/neutron/tests/unit/db/test_db_base_plugin_v2.py b/neutron/tests/unit/db/test_db_base_plugin_v2.py
index c4a1dce9ae..eb80348fbb 100644
--- a/neutron/tests/unit/db/test_db_base_plugin_v2.py
+++ b/neutron/tests/unit/db/test_db_base_plugin_v2.py
@@ -517,7 +517,7 @@ class NeutronDbPluginV2TestCase(testlib_api.WebTestCase):
'mac_address', 'name', 'fixed_ips',
'tenant_id', 'device_owner', 'security_groups',
'propagate_uplink_status', 'numa_affinity_policy',
- 'device_profile') + (arg_list or ())):
+ 'device_profile', 'hints') + (arg_list or ())):
# Arg must be present
if arg in kwargs:
data['port'][arg] = kwargs[arg]
diff --git a/neutron/tests/unit/extensions/test_port_hints.py b/neutron/tests/unit/extensions/test_port_hints.py
new file mode 100644
index 0000000000..9aa9fb1462
--- /dev/null
+++ b/neutron/tests/unit/extensions/test_port_hints.py
@@ -0,0 +1,85 @@
+# Copyright 2023 Ericsson Software Technology
+#
+# 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 ddt
+from neutron_lib.api.definitions import port_hints as phints_def
+from neutron_lib.db import api as db_api
+
+from neutron.db import db_base_plugin_v2
+from neutron.db import port_hints_db as phints_db
+from neutron.tests.unit.db import test_db_base_plugin_v2
+
+HINTS_LIST = [
+ None,
+ {'openvswitch': {'other_config': {'tx-steering': 'hash'}}},
+]
+
+
+class PortHintsExtensionTestPlugin(
+ db_base_plugin_v2.NeutronDbPluginV2,
+ phints_db.PortHintsMixin):
+ """Test plugin to mixin the port hints extension."""
+
+ supported_extension_aliases = [phints_def.ALIAS]
+
+ def create_port(self, context, port):
+ with db_api.CONTEXT_WRITER.using(context):
+ new_port = super(PortHintsExtensionTestPlugin,
+ self).create_port(context, port)
+ self._process_create_port(context, port['port'], new_port)
+ return new_port
+
+ def update_port(self, context, id, port):
+ with db_api.CONTEXT_WRITER.using(context):
+ updated_port = super(
+ PortHintsExtensionTestPlugin,
+ self).update_port(context, id, port)
+ self._process_update_port(context, port['port'], updated_port)
+ return updated_port
+
+
+@ddt.ddt
+class PortHintsExtensionTestCase(
+ test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
+ """Test API extension port-hints attributes."""
+
+ def setUp(self, *args):
+ plugin = ('neutron.tests.unit.extensions.test_port_hints.'
+ 'PortHintsExtensionTestPlugin')
+ super(PortHintsExtensionTestCase, self).setUp(plugin=plugin)
+
+ def _create_and_check_port_hints(self, hints):
+ keys = [('name', 'name_1'),
+ ('admin_state_up', True),
+ ('status', self.port_create_status),
+ ('hints', hints)]
+ with self.port(is_admin=True, name='name_1', hints=hints) as port:
+ for k, v in keys:
+ self.assertEqual(v, port['port'][k])
+ return port
+
+ def _update_and_check_port_hints(self, port, hints):
+ data = {'port': {'hints': hints}}
+ req = self.new_update_request(
+ 'ports', data, port['port']['id'], as_admin=True)
+ res = self.deserialize(self.fmt, req.get_response(self.api))
+ self.assertEqual(
+ hints, res['port']['hints'])
+
+ @ddt.data(*HINTS_LIST)
+ def test_create_and_update_port_hints(
+ self, hints):
+ port = self._create_and_check_port_hints(hints)
+ for new_hints in HINTS_LIST:
+ self._update_and_check_port_hints(port, new_hints)
diff --git a/neutron/tests/unit/objects/port/extensions/test_port_hints.py b/neutron/tests/unit/objects/port/extensions/test_port_hints.py
new file mode 100644
index 0000000000..2efd985388
--- /dev/null
+++ b/neutron/tests/unit/objects/port/extensions/test_port_hints.py
@@ -0,0 +1,33 @@
+# Copyright 2023 Ericsson Software Technology
+#
+# 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.objects.port.extensions import port_hints
+from neutron.tests.unit.objects import test_base as obj_test_base
+from neutron.tests.unit import testlib_api
+
+
+class PortHintsIfaceObjectTestCase(obj_test_base.BaseObjectIfaceTestCase):
+
+ _test_class = port_hints.PortHints
+
+
+class PortHintsDbObjectTestCase(
+ obj_test_base.BaseDbObjectTestCase, testlib_api.SqlTestCase):
+
+ _test_class = port_hints.PortHints
+
+ def setUp(self):
+ super(PortHintsDbObjectTestCase, self).setUp()
+ self.update_obj_fields(
+ {'port_id': lambda: self._create_test_port_id()})
diff --git a/neutron/tests/unit/objects/test_objects.py b/neutron/tests/unit/objects/test_objects.py
index d6a431e108..d198bae2b7 100644
--- a/neutron/tests/unit/objects/test_objects.py
+++ b/neutron/tests/unit/objects/test_objects.py
@@ -73,8 +73,9 @@ object_data = {
'NetworkSegment': '1.0-57b7f2960971e3b95ded20cbc59244a8',
'NetworkSegmentRange': '1.0-bdec1fffc9058ea676089b1f2f2b3cf3',
'NetworkSubnetLock': '1.0-140de39d4b86ae346dc3d70b885bea53',
- 'Port': '1.7-d8c1cfe42cfa3719a5d810eeab79e006',
+ 'Port': '1.8-1aa850ab5529128de07e82c6fb75fcb5',
'PortDeviceProfile': '1.0-b98c7083cc3e93d176fd7a91ae13af32',
+ 'PortHints': '1.0-9ebf6e12fa427809476a92c7432352b8',
'PortNumaAffinityPolicy': '1.0-38fcea43e7bfb2536461f3d053c43aa3',
'PortBinding': '1.0-3306deeaa6deb01e33af06777d48d578',
'PortBindingLevel': '1.1-50d47f63218f87581b6cd9a62db574e5',
diff --git a/neutron/tests/unit/objects/test_ports.py b/neutron/tests/unit/objects/test_ports.py
index b01fb998ed..f38077d8d0 100644
--- a/neutron/tests/unit/objects/test_ports.py
+++ b/neutron/tests/unit/objects/test_ports.py
@@ -529,6 +529,12 @@ class PortDbObjectTestCase(obj_test_base.BaseDbObjectTestCase,
self.assertNotIn('device_profile',
port_v1_6['versioned_object.data'])
+ def test_v1_8_to_v1_7_drops_hints(self):
+ port_new = self._create_test_port()
+ port_v1_7 = port_new.obj_to_primitive(target_version='1.7')
+ self.assertNotIn('hints',
+ port_v1_7['versioned_object.data'])
+
def test_get_ports_ids_by_security_groups_except_router(self):
sg_id = self._create_test_security_group_id()
filter_owner = constants.ROUTER_INTERFACE_OWNERS_SNAT
diff --git a/requirements.txt b/requirements.txt
index 2b2d62fbb9..73796c43eb 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -20,7 +20,7 @@ Jinja2>=2.10 # BSD License (3 clause)
keystonemiddleware>=5.1.0 # Apache-2.0
netaddr>=0.7.18 # BSD
netifaces>=0.10.4 # MIT
-neutron-lib>=3.4.0 # Apache-2.0
+neutron-lib>=3.5.0 # Apache-2.0
python-neutronclient>=7.8.0 # Apache-2.0
tenacity>=6.0.0 # Apache-2.0
SQLAlchemy>=1.4.23 # MIT
diff --git a/setup.cfg b/setup.cfg
index da9e0c0949..66edcd4575 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -125,6 +125,7 @@ neutron.ml2.extension_drivers =
tag_ports_during_bulk_creation = neutron.plugins.ml2.extensions.tag_ports_during_bulk_creation:TagPortsDuringBulkCreationExtensionDriver
subnet_dns_publish_fixed_ip = neutron.plugins.ml2.extensions.subnet_dns_publish_fixed_ip:SubnetDNSPublishFixedIPExtensionDriver
dns_domain_keywords = neutron.plugins.ml2.extensions.dns_domain_keywords:DnsDomainKeywordsExtensionDriver
+ port_hints = neutron.plugins.ml2.extensions.port_hints:PortHintsExtensionDriver
neutron.ipam_drivers =
fake = neutron.tests.unit.ipam.fake_driver:FakeDriver
internal = neutron.ipam.drivers.neutrondb_ipam.driver:NeutronDbPool