diff --git a/ironic/common/release_mappings.py b/ironic/common/release_mappings.py index cc4592fa99..3b143b445c 100644 --- a/ironic/common/release_mappings.py +++ b/ironic/common/release_mappings.py @@ -75,7 +75,7 @@ RELEASE_MAPPING = { 'Node': '1.21', 'Conductor': '1.2', 'Chassis': '1.3', - 'Port': '1.6', + 'Port': '1.7', 'Portgroup': '1.3', 'VolumeConnector': '1.0', 'VolumeTarget': '1.0', diff --git a/ironic/db/sqlalchemy/alembic/versions/3d86a077a3f2_add_port_physical_network.py b/ironic/db/sqlalchemy/alembic/versions/3d86a077a3f2_add_port_physical_network.py new file mode 100644 index 0000000000..b23c7ab68b --- /dev/null +++ b/ironic/db/sqlalchemy/alembic/versions/3d86a077a3f2_add_port_physical_network.py @@ -0,0 +1,32 @@ +# 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. + +"""add port physical network + +Revision ID: 3d86a077a3f2 +Revises: dbefd6bdaa2c +Create Date: 2017-04-30 17:11:49.384851 + +""" + +# revision identifiers, used by Alembic. +revision = '3d86a077a3f2' +down_revision = 'dbefd6bdaa2c' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.add_column('ports', sa.Column('physical_network', + sa.String(64), + nullable=True)) diff --git a/ironic/db/sqlalchemy/models.py b/ironic/db/sqlalchemy/models.py index 1d90d1bfe4..f5f13ffe6c 100644 --- a/ironic/db/sqlalchemy/models.py +++ b/ironic/db/sqlalchemy/models.py @@ -195,6 +195,7 @@ class Port(Base): portgroup_id = Column(Integer, ForeignKey('portgroups.id'), nullable=True) pxe_enabled = Column(Boolean, default=True) internal_info = Column(db_types.JsonEncodedDict) + physical_network = Column(String(64), nullable=True) class Portgroup(Base): diff --git a/ironic/objects/port.py b/ironic/objects/port.py index 06a24e73c7..b1d0230731 100644 --- a/ironic/objects/port.py +++ b/ironic/objects/port.py @@ -36,7 +36,8 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat): # Version 1.5: Add list_by_portgroup_id() and new fields # local_link_connection, portgroup_id and pxe_enabled # Version 1.6: Add internal_info field - VERSION = '1.6' + # Version 1.7: Add physical_network field + VERSION = '1.7' dbapi = dbapi.get_instance() @@ -51,6 +52,7 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat): 'portgroup_id': object_fields.IntegerField(nullable=True), 'pxe_enabled': object_fields.BooleanField(), 'internal_info': object_fields.FlexibleDictField(nullable=True), + 'physical_network': object_fields.StringField(nullable=True), } # NOTE(xek): We don't want to enable RPC on this call just yet. Remotable diff --git a/ironic/tests/unit/api/utils.py b/ironic/tests/unit/api/utils.py index 702a7c9433..4f3934c4b5 100644 --- a/ironic/tests/unit/api/utils.py +++ b/ironic/tests/unit/api/utils.py @@ -117,6 +117,8 @@ def port_post_data(**kw): port.pop('node_id') # portgroup_id is not part of the API object port.pop('portgroup_id') + # NOTE(mgoddard): Physical network is not yet supported by the REST API. + port.pop('physical_network') internal = port_controller.PortPatchType.internal_attrs() return remove_internal(port, internal) diff --git a/ironic/tests/unit/api/v1/test_ports.py b/ironic/tests/unit/api/v1/test_ports.py index 13d3a43dda..31d1970bed 100644 --- a/ironic/tests/unit/api/v1/test_ports.py +++ b/ironic/tests/unit/api/v1/test_ports.py @@ -257,6 +257,9 @@ class TestListPorts(test_api_base.BaseApiTest): # never expose the node_id and portgroup_id self.assertNotIn('node_id', data['ports'][0]) self.assertNotIn('portgroup_id', data['ports'][0]) + # NOTE(mgoddard): The physical network attribute is not yet exposed by + # the API. + self.assertNotIn('physical_network', data['ports'][0]) def test_detail_against_single(self): port = obj_utils.create_test_port(self.context, node_id=self.node.id) diff --git a/ironic/tests/unit/db/sqlalchemy/test_migrations.py b/ironic/tests/unit/db/sqlalchemy/test_migrations.py index baf312ed4c..812e79bf95 100644 --- a/ironic/tests/unit/db/sqlalchemy/test_migrations.py +++ b/ironic/tests/unit/db/sqlalchemy/test_migrations.py @@ -634,6 +634,13 @@ class MigrationCheckersMixin(object): (sqlalchemy.types.Boolean, sqlalchemy.types.Integer)) + def _check_3d86a077a3f2(self, engine, data): + ports = db_utils.get_table(engine, 'ports') + col_names = [column.name for column in ports.c] + self.assertIn('physical_network', col_names) + self.assertIsInstance(ports.c.physical_network.type, + sqlalchemy.types.String) + def test_upgrade_and_version(self): with patch_with_engine(self.engine): self.migration_api.upgrade('head') diff --git a/ironic/tests/unit/db/utils.py b/ironic/tests/unit/db/utils.py index 0d00f3d962..55239641cc 100644 --- a/ironic/tests/unit/db/utils.py +++ b/ironic/tests/unit/db/utils.py @@ -260,6 +260,7 @@ def get_test_port(**kw): 'portgroup_id': kw.get('portgroup_id'), 'pxe_enabled': kw.get('pxe_enabled', True), 'internal_info': kw.get('internal_info', {"bar": "buzz"}), + 'physical_network': kw.get('physical_network'), } diff --git a/ironic/tests/unit/objects/test_objects.py b/ironic/tests/unit/objects/test_objects.py index ff7de1e245..27f23f2462 100644 --- a/ironic/tests/unit/objects/test_objects.py +++ b/ironic/tests/unit/objects/test_objects.py @@ -411,7 +411,7 @@ expected_object_fingerprints = { 'Node': '1.21-52674c214141cf3e09f8688bfed54577', 'MyObj': '1.5-4f5efe8f0fcaf182bbe1c7fe3ba858db', 'Chassis': '1.3-d656e039fd8ae9f34efc232ab3980905', - 'Port': '1.6-609504503d68982a10f495659990084b', + 'Port': '1.7-898a47921f4a1f53fcdddd4eeb179e0b', 'Portgroup': '1.3-71923a81a86743b313b190f5c675e258', 'Conductor': '1.2-5091f249719d4a465062a1b3dc7f860d', 'EventType': '1.1-aa2ba1afd38553e3880c267404e8d370',