diff --git a/ironic/objects/port.py b/ironic/objects/port.py index 1bfbb744d5..0983887296 100644 --- a/ironic/objects/port.py +++ b/ironic/objects/port.py @@ -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. diff --git a/ironic/tests/unit/objects/test_port.py b/ironic/tests/unit/objects/test_port.py index 1511cf08b6..abe1758679 100644 --- a/ironic/tests/unit/objects/test_port.py +++ b/ironic/tests/unit/objects/test_port.py @@ -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())