diff --git a/neutron/db/migration/alembic_migrations/versions/EXPAND_HEAD b/neutron/db/migration/alembic_migrations/versions/EXPAND_HEAD index 8a2025caffd..f0871630e7a 100644 --- a/neutron/db/migration/alembic_migrations/versions/EXPAND_HEAD +++ b/neutron/db/migration/alembic_migrations/versions/EXPAND_HEAD @@ -1 +1 @@ -263d454a9655 +Ibac91d24da2 diff --git a/neutron/db/migration/alembic_migrations/versions/ussuri/expand/Ibac91d24da2_port_forwarding_description.py b/neutron/db/migration/alembic_migrations/versions/ussuri/expand/Ibac91d24da2_port_forwarding_description.py new file mode 100644 index 00000000000..65528d8abe6 --- /dev/null +++ b/neutron/db/migration/alembic_migrations/versions/ussuri/expand/Ibac91d24da2_port_forwarding_description.py @@ -0,0 +1,77 @@ +# Copyright 2019 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. +# + +import sqlalchemy as sa + +from alembic import op + +"""port forwarding rule description + +Revision ID: Ibac91d24da2 +Revises: 263d454a9655 +Create Date: 2019-07-13 10:00:00.000000 + +""" + +# revision identifiers, used by Alembic. +revision = 'Ibac91d24da2' +down_revision = '263d454a9655' + +TABLE_NAME = 'portforwardings' + +TABLE_MODEL = sa.Table(TABLE_NAME, sa.MetaData(), + sa.Column('id', sa.String(length=36), nullable=False), + sa.Column('standard_attr_id', sa.BigInteger(), + nullable=True)) + +STDATTRS_TABLE = sa.Table( + 'standardattributes', sa.MetaData(), + sa.Column('id', sa.BigInteger(), primary_key=True, autoincrement=True), + sa.Column('resource_type', sa.String(length=255), nullable=False)) + + +def update_existing_records(): + session = sa.orm.Session(bind=op.get_bind()) + with session.begin(subtransactions=True): + for row in session.query(TABLE_MODEL): + res = session.execute( + STDATTRS_TABLE.insert().values(resource_type=TABLE_NAME) + ) + session.execute( + TABLE_MODEL.update().values( + standard_attr_id=res.inserted_primary_key[0]).where( + TABLE_MODEL.c.id == row[0]) + ) + session.commit() + + +def upgrade(): + op.add_column(TABLE_NAME, sa.Column('standard_attr_id', + sa.BigInteger(), + nullable=True)) + update_existing_records() + + op.alter_column(TABLE_NAME, 'standard_attr_id', nullable=False, + existing_type=sa.BigInteger(), existing_nullable=True, + existing_server_default=False) + + op.create_foreign_key( + constraint_name=None, source_table=TABLE_NAME, + referent_table='standardattributes', + local_cols=['standard_attr_id'], remote_cols=['id'], + ondelete='CASCADE') + op.create_unique_constraint( + constraint_name='uniq_%s0standard_attr_id' % TABLE_NAME, + table_name=TABLE_NAME, columns=['standard_attr_id']) diff --git a/neutron/db/models/port_forwarding.py b/neutron/db/models/port_forwarding.py index 03ee166fc4a..9b11551cd81 100644 --- a/neutron/db/models/port_forwarding.py +++ b/neutron/db/models/port_forwarding.py @@ -19,10 +19,13 @@ from sqlalchemy import orm from neutron.db.models import l3 from neutron.db import models_v2 +from neutron.db import standard_attr +from neutron_lib.api.definitions import fip_pf_description as apidef from neutron_lib.db import constants as db_const -class PortForwarding(model_base.BASEV2, model_base.HasId): +class PortForwarding(standard_attr.HasStandardAttributes, + model_base.BASEV2, model_base.HasId): __table_args__ = ( sa.UniqueConstraint('floatingip_id', 'external_port', 'protocol', @@ -58,3 +61,4 @@ class PortForwarding(model_base.BASEV2, model_base.HasId): cascade='delete') ) revises_on_change = ('floating_ip', 'port',) + api_collections = [apidef.ALIAS] diff --git a/neutron/objects/port_forwarding.py b/neutron/objects/port_forwarding.py index 2348fb5a3bd..f18a5ad30ea 100644 --- a/neutron/objects/port_forwarding.py +++ b/neutron/objects/port_forwarding.py @@ -22,6 +22,7 @@ from neutron.db.models import port_forwarding as models from neutron.objects import base from neutron.objects import router from neutron_lib import constants as lib_const +from oslo_utils import versionutils from oslo_versionedobjects import fields as obj_fields FIELDS_NOT_SUPPORT_FILTER = ['internal_ip_address', 'internal_port'] @@ -31,7 +32,8 @@ FIELDS_NOT_SUPPORT_FILTER = ['internal_ip_address', 'internal_port'] class PortForwarding(base.NeutronDbObject): # Version 1.0: Initial version # Version 1.1: Change unique constraint - VERSION = '1.1' + # Version 1.2: Add "description" field + VERSION = '1.2' db_model = models.PortForwarding @@ -61,9 +63,13 @@ class PortForwarding(base.NeutronDbObject): 'internal_ip_address': obj_fields.IPV4AddressField(), 'internal_port': common_types.PortRangeField(nullable=False), 'floating_ip_address': obj_fields.IPV4AddressField(), - 'router_id': common_types.UUIDField() + 'router_id': common_types.UUIDField(), + 'description': obj_fields.StringField() } + comparision_ignored_fields = ['revision_number', 'updated_at', + 'created_at'] + synthetic_fields = ['floating_ip_address', 'router_id'] fields_no_update = { 'id', 'floatingip_id' @@ -71,6 +77,11 @@ class PortForwarding(base.NeutronDbObject): def __eq__(self, other): for attr in self.fields: + # Some fields are inherited from standards attributes and are + # irrelevant while comparing two PortForwarding. + if attr in self.comparision_ignored_fields: + continue + if getattr(self, attr) != getattr(other, attr): return False return True @@ -93,6 +104,11 @@ class PortForwarding(base.NeutronDbObject): self._load_attr_from_fip(attrname='router_id') self._load_attr_from_fip(attrname='floating_ip_address') + def obj_make_compatible(self, primitive, target_version): + _target_version = versionutils.convert_version_to_tuple(target_version) + if _target_version < (1, 2): + primitive.pop('description', None) + @classmethod def modify_fields_from_db(cls, db_obj): result = super(PortForwarding, cls).modify_fields_from_db(db_obj) diff --git a/neutron/tests/functional/services/portforwarding/test_port_forwarding.py b/neutron/tests/functional/services/portforwarding/test_port_forwarding.py index f80f333b493..29a944a86d2 100644 --- a/neutron/tests/functional/services/portforwarding/test_port_forwarding.py +++ b/neutron/tests/functional/services/portforwarding/test_port_forwarding.py @@ -11,6 +11,7 @@ # under the License. import mock +from neutron_lib.api.definitions import fip_pf_description as ext_apidef from neutron_lib.api.definitions import floating_ip_port_forwarding as apidef from neutron_lib.callbacks import exceptions as c_exc from neutron_lib import exceptions as lib_exc @@ -121,6 +122,7 @@ class PortForwardingTestCase(PortForwardingTestCaseBase): apidef.INTERNAL_PORT: 25, apidef.INTERNAL_PORT_ID: self.port['id'], apidef.PROTOCOL: "tcp", + ext_apidef.DESCRIPTION_FIELD: 'Some description', apidef.INTERNAL_IP_ADDRESS: self.port['fixed_ips'][0]['ip_address']}} @@ -143,6 +145,9 @@ class PortForwardingTestCase(PortForwardingTestCaseBase): 'id': mock.ANY, 'router_id': self.router['id'], 'floating_ip_address': self.fip['floating_ip_address'], + 'description': 'Some description', + 'revision_number': 0, + 'created_at': mock.ANY, 'floatingip_id': self.fip['id']} self.assertEqual(expect, res) @@ -202,6 +207,9 @@ class PortForwardingTestCase(PortForwardingTestCaseBase): 'id': mock.ANY, 'router_id': self.router['id'], 'floating_ip_address': self.fip['floating_ip_address'], + 'description': 'Some description', + 'revision_number': 0, + 'created_at': mock.ANY, 'floatingip_id': self.fip['id']} self.assertEqual(expect, res) @@ -240,6 +248,9 @@ class PortForwardingTestCase(PortForwardingTestCaseBase): 'id': res['id'], 'router_id': self.router['id'], 'floating_ip_address': self.fip['floating_ip_address'], + 'description': 'Some description', + 'revision_number': 0, + 'created_at': mock.ANY, 'floatingip_id': self.fip['id']} self.assertEqual(expect, update_res) @@ -265,6 +276,9 @@ class PortForwardingTestCase(PortForwardingTestCaseBase): 'id': res['id'], 'router_id': self.router['id'], 'floating_ip_address': self.fip['floating_ip_address'], + 'description': 'Some description', + 'revision_number': 0, + 'created_at': mock.ANY, 'floatingip_id': self.fip['id']} self.assertEqual(expect, update_res) @@ -448,6 +462,9 @@ class PortForwardingTestCase(PortForwardingTestCaseBase): 'id': mock.ANY, 'router_id': self.router['id'], 'floating_ip_address': self.fip['floating_ip_address'], + 'description': 'Some description', + 'revision_number': 0, + 'created_at': mock.ANY, 'floatingip_id': self.fip['id']} self.assertEqual(expected, res) diff --git a/neutron/tests/unit/agent/l3/extensions/test_port_forwarding.py b/neutron/tests/unit/agent/l3/extensions/test_port_forwarding.py index 765a91e8f94..a9d28f37884 100644 --- a/neutron/tests/unit/agent/l3/extensions/test_port_forwarding.py +++ b/neutron/tests/unit/agent/l3/extensions/test_port_forwarding.py @@ -312,25 +312,29 @@ class RouterFipPortForwardingMappingTestCase(base.BaseTestCase): external_port=1111, protocol='tcp', internal_port_id=_uuid(), internal_ip_address='1.1.1.1', internal_port=11111, floating_ip_address='111.111.111.111', - router_id=self.router1) + router_id=self.router1, + description='Some description') self.portforwarding2 = pf_obj.PortForwarding( context=None, id=_uuid(), floatingip_id=self.floatingip1, external_port=1112, protocol='tcp', internal_port_id=_uuid(), internal_ip_address='1.1.1.2', internal_port=11112, floating_ip_address='111.111.111.111', - router_id=self.router1) + router_id=self.router1, + description='Some description') self.portforwarding3 = pf_obj.PortForwarding( context=None, id=_uuid(), floatingip_id=self.floatingip2, external_port=1113, protocol='tcp', internal_port_id=_uuid(), internal_ip_address='1.1.1.3', internal_port=11113, floating_ip_address='111.222.111.222', - router_id=self.router1) + router_id=self.router1, + description=None) self.portforwarding4 = pf_obj.PortForwarding( context=None, id=_uuid(), floatingip_id=self.floatingip3, external_port=2222, protocol='tcp', internal_port_id=_uuid(), internal_ip_address='2.2.2.2', internal_port=22222, floating_ip_address='222.222.222.222', - router_id=self.router2) + router_id=self.router2, + description='') self.portforwardings_dict = { self.portforwarding1.id: self.portforwarding1, self.portforwarding2.id: self.portforwarding2, @@ -376,6 +380,7 @@ class RouterFipPortForwardingMappingTestCase(base.BaseTestCase): def test_update_port_forwarding(self): self._set_pf() + description = 'Some description' new_pf1 = pf_obj.PortForwarding( context=None, id=self.portforwarding2.id, floatingip_id=self.floatingip1, @@ -383,7 +388,8 @@ class RouterFipPortForwardingMappingTestCase(base.BaseTestCase): internal_port_id=self.portforwarding2.internal_port_id, internal_ip_address='1.1.1.22', internal_port=11122, floating_ip_address='111.111.111.111', - router_id=self.router1) + router_id=self.router1, + description=description) self.mapping.update_port_forwardings([new_pf1]) self.assertEqual( new_pf1, diff --git a/neutron/tests/unit/objects/test_objects.py b/neutron/tests/unit/objects/test_objects.py index 6b44078f2ec..001b6adfdf1 100644 --- a/neutron/tests/unit/objects/test_objects.py +++ b/neutron/tests/unit/objects/test_objects.py @@ -70,7 +70,7 @@ object_data = { 'PortBindingLevel': '1.1-50d47f63218f87581b6cd9a62db574e5', 'PortDataPlaneStatus': '1.0-25be74bda46c749653a10357676c0ab2', 'PortDNS': '1.1-c5ca2dc172bdd5fafee3fc986d1d7023', - 'PortForwarding': '1.1-db61273978c497239be5389a8aeb1c61', + 'PortForwarding': '1.2-f772f03b82a616603c7f3d4497bf577f', 'PortSecurity': '1.0-b30802391a87945ee9c07582b4ff95e3', 'PortUplinkStatusPropagation': '1.0-3cfb3f7da716ca9687e4f04ca72b081d', 'ProviderResourceAssociation': '1.0-05ab2d5a3017e5ce9dd381328f285f34', diff --git a/releasenotes/notes/add-description-field-in-port-forwarding-5db3b3f407c7eef4.yaml b/releasenotes/notes/add-description-field-in-port-forwarding-5db3b3f407c7eef4.yaml new file mode 100644 index 00000000000..5ae37f629ab --- /dev/null +++ b/releasenotes/notes/add-description-field-in-port-forwarding-5db3b3f407c7eef4.yaml @@ -0,0 +1,4 @@ +--- +features: + - | + Add a new field ``description`` to the ``PortForwarding`` resource. \ No newline at end of file