Add description field to portforwarding NAT rules

Add the `description` field to `PortForwardings`
using the standard attributes like in the
`FloatingIPs`.

Depends-On: https://review.opendev.org/#/c/692580/
Depends-On: https://review.opendev.org/#/c/698662/
Implements: blueprint portforwarding-description
Closes-Bug: #1850818
Change-Id: Ibac91d24da2b82cdce72165d1295fa5d4475ffd3
Signed-off-by: Pedro Martins <phpm13@gmail.com>
This commit is contained in:
Pedro Henrique 2019-07-14 17:51:09 -03:00 committed by pedro
parent 0115f71af8
commit 06e43dd95d
8 changed files with 134 additions and 10 deletions

View File

@ -1 +1 @@
263d454a9655
Ibac91d24da2

View File

@ -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'])

View File

@ -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]

View File

@ -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)

View File

@ -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)

View File

@ -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,

View File

@ -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',

View File

@ -0,0 +1,4 @@
---
features:
- |
Add a new field ``description`` to the ``PortForwarding`` resource.