From 9e938f24668e49216b4cb135770899a50d627914 Mon Sep 17 00:00:00 2001 From: Dmitry Tantsur Date: Fri, 11 Nov 2016 16:40:46 +0100 Subject: [PATCH] Add node (database and objects) fields for all interfaces For the driver composition reform we need nodes to record hardware interfaces they're using. This change adds necessary fields. The new fields will have a default value of None, which is the expected value for nodes using classic drivers. The new fields are not added to notifications yet, as they're not wired in. Change-Id: Id7697de0276e9b2730ea62f9c562ed6e1d0f8a06 Partial-Bug: #1524745 --- ...d431ba0bf_add_fields_for_all_interfaces.py | 45 +++++++++++++++++++ ironic/db/sqlalchemy/models.py | 8 ++++ ironic/drivers/base.py | 7 +++ ironic/objects/node.py | 13 +++++- ironic/tests/unit/api/utils.py | 7 ++- .../unit/db/sqlalchemy/test_migrations.py | 10 +++++ ironic/tests/unit/db/utils.py | 10 ++++- ironic/tests/unit/objects/test_objects.py | 2 +- .../interface-fields-f4b9384fdda6189a.yaml | 4 ++ 9 files changed, 100 insertions(+), 6 deletions(-) create mode 100644 ironic/db/sqlalchemy/alembic/versions/bcdd431ba0bf_add_fields_for_all_interfaces.py create mode 100644 releasenotes/notes/interface-fields-f4b9384fdda6189a.yaml diff --git a/ironic/db/sqlalchemy/alembic/versions/bcdd431ba0bf_add_fields_for_all_interfaces.py b/ironic/db/sqlalchemy/alembic/versions/bcdd431ba0bf_add_fields_for_all_interfaces.py new file mode 100644 index 0000000000..6c5db9224e --- /dev/null +++ b/ironic/db/sqlalchemy/alembic/versions/bcdd431ba0bf_add_fields_for_all_interfaces.py @@ -0,0 +1,45 @@ +# 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 fields for all interfaces + +Revision ID: bcdd431ba0bf +Revises: 60cf717201bc +Create Date: 2016-11-11 16:44:52.823881 + +""" + +# revision identifiers, used by Alembic. +revision = 'bcdd431ba0bf' +down_revision = '60cf717201bc' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.add_column('nodes', sa.Column('boot_interface', + sa.String(length=255), nullable=True)) + op.add_column('nodes', sa.Column('console_interface', + sa.String(length=255), nullable=True)) + op.add_column('nodes', sa.Column('deploy_interface', + sa.String(length=255), nullable=True)) + op.add_column('nodes', sa.Column('inspect_interface', + sa.String(length=255), nullable=True)) + op.add_column('nodes', sa.Column('management_interface', + sa.String(length=255), nullable=True)) + op.add_column('nodes', sa.Column('power_interface', + sa.String(length=255), nullable=True)) + op.add_column('nodes', sa.Column('raid_interface', + sa.String(length=255), nullable=True)) + op.add_column('nodes', sa.Column('vendor_interface', + sa.String(length=255), nullable=True)) diff --git a/ironic/db/sqlalchemy/models.py b/ironic/db/sqlalchemy/models.py index b3a5e46ff0..2fbe87d7ce 100644 --- a/ironic/db/sqlalchemy/models.py +++ b/ironic/db/sqlalchemy/models.py @@ -144,7 +144,15 @@ class Node(Base): inspection_started_at = Column(DateTime, nullable=True) extra = Column(db_types.JsonEncodedDict) + boot_interface = Column(String(255), nullable=True) + console_interface = Column(String(255), nullable=True) + deploy_interface = Column(String(255), nullable=True) + inspect_interface = Column(String(255), nullable=True) + management_interface = Column(String(255), nullable=True) network_interface = Column(String(255), nullable=True) + raid_interface = Column(String(255), nullable=True) + power_interface = Column(String(255), nullable=True) + vendor_interface = Column(String(255), nullable=True) class Port(Base): diff --git a/ironic/drivers/base.py b/ironic/drivers/base.py index f1285095cf..2d49f6fe2e 100644 --- a/ironic/drivers/base.py +++ b/ironic/drivers/base.py @@ -171,6 +171,13 @@ class BareDriver(BaseDriver): self.core_interfaces.append('network') +ALL_INTERFACES = set(BareDriver().all_interfaces) +"""Constant holding all known interfaces. + +Includes interfaces not exposed via BaseDriver.all_interfaces. +""" + + @six.add_metaclass(abc.ABCMeta) class BaseInterface(object): """A base interface implementing common functions for Driver Interfaces.""" diff --git a/ironic/objects/node.py b/ironic/objects/node.py index 40092d91b8..2f8b64311a 100644 --- a/ironic/objects/node.py +++ b/ironic/objects/node.py @@ -58,7 +58,10 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat): # Version 1.16: Add network_interface field # Version 1.17: Add resource_class field # Version 1.18: Add default setting for network_interface - VERSION = '1.18' + # Version 1.19: Add fields: boot_interface, console_interface, + # deploy_interface, inspect_interface, management_interface, + # power_interface, raid_interface, vendor_interface + VERSION = '1.19' dbapi = db_api.get_instance() @@ -118,8 +121,16 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat): 'extra': object_fields.FlexibleDictField(nullable=True), + 'boot_interface': object_fields.StringField(nullable=True), + 'console_interface': object_fields.StringField(nullable=True), + 'deploy_interface': object_fields.StringField(nullable=True), + 'inspect_interface': object_fields.StringField(nullable=True), + 'management_interface': object_fields.StringField(nullable=True), 'network_interface': object_fields.StringFieldThatAcceptsCallable( nullable=False, default=_default_network_interface), + 'power_interface': object_fields.StringField(nullable=True), + 'raid_interface': object_fields.StringField(nullable=True), + 'vendor_interface': object_fields.StringField(nullable=True), } def _validate_property_values(self, properties): diff --git a/ironic/tests/unit/api/utils.py b/ironic/tests/unit/api/utils.py index 3f70d7410b..e9193a524a 100644 --- a/ironic/tests/unit/api/utils.py +++ b/ironic/tests/unit/api/utils.py @@ -23,6 +23,7 @@ from ironic.api.controllers.v1 import chassis as chassis_controller from ironic.api.controllers.v1 import node as node_controller from ironic.api.controllers.v1 import port as port_controller from ironic.api.controllers.v1 import portgroup as portgroup_controller +from ironic.drivers import base as drivers_base from ironic.tests.unit.db import utils ADMIN_TOKEN = '4562138218392831' @@ -99,8 +100,10 @@ def node_post_data(**kw): # NOTE(jroll): pop out fields that were introduced in later API versions, # unless explicitly requested. Otherwise, these will cause tests using # older API versions to fail. - if 'network_interface' not in kw: - node.pop('network_interface') + for iface in drivers_base.ALL_INTERFACES: + name = '%s_interface' % iface + if name not in kw: + node.pop(name) if 'resource_class' not in kw: node.pop('resource_class') diff --git a/ironic/tests/unit/db/sqlalchemy/test_migrations.py b/ironic/tests/unit/db/sqlalchemy/test_migrations.py index e499f4284b..e0c464b590 100644 --- a/ironic/tests/unit/db/sqlalchemy/test_migrations.py +++ b/ironic/tests/unit/db/sqlalchemy/test_migrations.py @@ -53,6 +53,7 @@ import sqlalchemy.exc from ironic.common.i18n import _LE from ironic.db.sqlalchemy import migration from ironic.db.sqlalchemy import models +from ironic.drivers import base as base_driver from ironic.tests import base LOG = logging.getLogger(__name__) @@ -537,6 +538,15 @@ class MigrationCheckersMixin(object): (sqlalchemy.types.Boolean, sqlalchemy.types.Integer)) + def _check_bcdd431ba0bf(self, engine, data): + nodes = db_utils.get_table(engine, 'nodes') + col_names = [column.name for column in nodes.c] + for iface in base_driver.ALL_INTERFACES: + name = '%s_interface' % iface + self.assertIn(name, col_names) + self.assertIsInstance(getattr(nodes.c, name).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 fc626a87ae..72fe659fa8 100644 --- a/ironic/tests/unit/db/utils.py +++ b/ironic/tests/unit/db/utils.py @@ -19,6 +19,7 @@ from oslo_utils import timeutils from ironic.common import states from ironic.db import api as db_api +from ironic.drivers import base as drivers_base def get_test_ipmi_info(): @@ -214,7 +215,7 @@ def get_test_node(**kw): fake_internal_info = { "private_state": "secret value" } - return { + result = { 'id': kw.get('id', 123), 'name': kw.get('name', None), 'uuid': kw.get('uuid', '1be26c0b-03f2-4d2e-ae87-c02d7f33c123'), @@ -248,9 +249,14 @@ def get_test_node(**kw): 'target_raid_config': kw.get('target_raid_config'), 'tags': kw.get('tags', []), 'resource_class': kw.get('resource_class'), - 'network_interface': kw.get('network_interface'), } + for iface in drivers_base.ALL_INTERFACES: + name = '%s_interface' % iface + result[name] = kw.get(name) + + return result + def create_test_node(**kw): """Create test node entry in DB and return Node DB object. diff --git a/ironic/tests/unit/objects/test_objects.py b/ironic/tests/unit/objects/test_objects.py index 8fdc583e79..f5afdeeb13 100644 --- a/ironic/tests/unit/objects/test_objects.py +++ b/ironic/tests/unit/objects/test_objects.py @@ -404,7 +404,7 @@ class TestObject(_LocalTest, _TestObject): # version bump. It is md5 hash of object fields and remotable methods. # The fingerprint values should only be changed if there is a version bump. expected_object_fingerprints = { - 'Node': '1.18-37a1d39ba8a4957f505dda936ac9146b', + 'Node': '1.19-e8b294016d8d5b322df813f790d092b4', 'MyObj': '1.5-4f5efe8f0fcaf182bbe1c7fe3ba858db', 'Chassis': '1.3-d656e039fd8ae9f34efc232ab3980905', 'Port': '1.6-609504503d68982a10f495659990084b', diff --git a/releasenotes/notes/interface-fields-f4b9384fdda6189a.yaml b/releasenotes/notes/interface-fields-f4b9384fdda6189a.yaml new file mode 100644 index 0000000000..0989f4721f --- /dev/null +++ b/releasenotes/notes/interface-fields-f4b9384fdda6189a.yaml @@ -0,0 +1,4 @@ +--- +upgrade: + - Add database migration to add new fields corresponding to all interfaces + to the node table.