Rolling upgrades support for port.physical_network

The new field 'physical_network' was added to Port in version
1.7, and port creation was moved from the API to the conductor
service in commit 9e3f412186.

This adds objects.port.Port._convert_to_version().  The method handles
converting the new physical_network field between different versions of
the Port.

Change-Id: I8a5b1e3dd72884a511b43839cdb264354bc46ea0
Co-Authored-By: Mark Goddard <mark@stackhpc.com>
Related-Bug: #1666009
Related-Bug: #1526283
This commit is contained in:
Ruby Loo 2017-06-26 18:11:48 -04:00 committed by Mark Goddard
parent e718b837a0
commit 7e4030600f
2 changed files with 97 additions and 0 deletions

View File

@ -16,6 +16,7 @@
from oslo_utils import netutils
from oslo_utils import strutils
from oslo_utils import uuidutils
from oslo_utils import versionutils
from oslo_versionedobjects import base as object_base
from ironic.common import exception
@ -55,6 +56,41 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
'physical_network': object_fields.StringField(nullable=True),
}
def _convert_to_version(self, target_version,
remove_unavailable_fields=True):
"""Convert to the target version.
Convert the object to the target version. The target version may be
the same, older, or newer than the version of the object. This is
used for DB interactions as well as for serialization/deserialization.
Version 1.7: physical_network field was added. Its default value is
None. For versions prior to this, it should be set to None (or
removed).
:param target_version: the desired version of the object
:param remove_unavailable_fields: True to remove fields that are
unavailable in the target version; set this to True when
(de)serializing. False to set the unavailable fields to appropriate
values; set this to False for DB interactions.
"""
target_version = versionutils.convert_version_to_tuple(target_version)
# Convert the physical_network field.
physnet_is_set = self.obj_attr_is_set('physical_network')
if target_version >= (1, 7):
# Target version supports physical_network. Set it to its default
# value if it is not set.
if not physnet_is_set:
self.physical_network = None
elif physnet_is_set:
# Target version does not support physical_network, and it is set.
if remove_unavailable_fields:
# (De)serialising: remove unavailable fields.
delattr(self, 'physical_network')
elif self.physical_network is not None:
# DB: set unavailable fields to their default.
self.physical_network = None
# NOTE(xek): We don't want to enable RPC on this call just yet. Remotable
# methods can be used in the future to replace current explicit RPC calls.
# Implications of calling new remote procedures should be thought through.

View File

@ -160,3 +160,64 @@ class TestPortObject(db_base.DbTestCase, obj_utils.SchemasTestMixIn):
def test_payload_schemas(self):
self._check_payload_schemas(objects.port, objects.Port.fields)
class TestConvertToVersion(db_base.DbTestCase):
def setUp(self):
super(TestConvertToVersion, self).setUp()
self.fake_port = db_utils.get_test_port()
def test_physnet_supported_missing(self):
# Physical network not set, should be set to default.
port = objects.Port(self.context, **self.fake_port)
delattr(port, 'physical_network')
port.obj_reset_changes()
port._convert_to_version("1.7")
self.assertIsNone(port.physical_network)
self.assertEqual({'physical_network': None}, port.obj_get_changes())
def test_physnet_supported_set(self):
# Physical network set, no change required.
port = objects.Port(self.context, **self.fake_port)
port.physical_network = 'physnet1'
port.obj_reset_changes()
port._convert_to_version("1.7")
self.assertEqual('physnet1', port.physical_network)
self.assertEqual({}, port.obj_get_changes())
def test_physnet_unsupported_missing(self):
# Physical network not set, no change required.
port = objects.Port(self.context, **self.fake_port)
delattr(port, 'physical_network')
port.obj_reset_changes()
port._convert_to_version("1.6")
self.assertNotIn('physical_network', port)
self.assertEqual({}, port.obj_get_changes())
def test_physnet_unsupported_set_remove(self):
# Physical network set, should be removed.
port = objects.Port(self.context, **self.fake_port)
port.physical_network = 'physnet1'
port.obj_reset_changes()
port._convert_to_version("1.6")
self.assertNotIn('physical_network', port)
self.assertEqual({}, port.obj_get_changes())
def test_physnet_unsupported_set_no_remove_non_default(self):
# Physical network set, should be set to default.
port = objects.Port(self.context, **self.fake_port)
port.physical_network = 'physnet1'
port.obj_reset_changes()
port._convert_to_version("1.6", False)
self.assertIsNone(port.physical_network)
self.assertEqual({'physical_network': None}, port.obj_get_changes())
def test_physnet_unsupported_set_no_remove_default(self):
# Physical network set, no change required.
port = objects.Port(self.context, **self.fake_port)
port.physical_network = None
port.obj_reset_changes()
port._convert_to_version("1.6", False)
self.assertIsNone(port.physical_network)
self.assertEqual({}, port.obj_get_changes())