Merge "Add node (database and objects) fields for all interfaces"

This commit is contained in:
Jenkins 2016-11-21 21:21:25 +00:00 committed by Gerrit Code Review
commit c0308d8034
9 changed files with 100 additions and 6 deletions

View File

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

View File

@ -144,7 +144,15 @@ class Node(Base):
inspection_started_at = Column(DateTime, nullable=True) inspection_started_at = Column(DateTime, nullable=True)
extra = Column(db_types.JsonEncodedDict) 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) 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): class Port(Base):

View File

@ -171,6 +171,13 @@ class BareDriver(BaseDriver):
self.core_interfaces.append('network') 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) @six.add_metaclass(abc.ABCMeta)
class BaseInterface(object): class BaseInterface(object):
"""A base interface implementing common functions for Driver Interfaces.""" """A base interface implementing common functions for Driver Interfaces."""

View File

@ -58,7 +58,10 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):
# Version 1.16: Add network_interface field # Version 1.16: Add network_interface field
# Version 1.17: Add resource_class field # Version 1.17: Add resource_class field
# Version 1.18: Add default setting for network_interface # 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() dbapi = db_api.get_instance()
@ -118,8 +121,16 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):
'extra': object_fields.FlexibleDictField(nullable=True), '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( 'network_interface': object_fields.StringFieldThatAcceptsCallable(
nullable=False, default=_default_network_interface), 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): def _validate_property_values(self, properties):

View File

@ -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 node as node_controller
from ironic.api.controllers.v1 import port as port_controller from ironic.api.controllers.v1 import port as port_controller
from ironic.api.controllers.v1 import portgroup as portgroup_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 from ironic.tests.unit.db import utils
ADMIN_TOKEN = '4562138218392831' ADMIN_TOKEN = '4562138218392831'
@ -99,8 +100,10 @@ def node_post_data(**kw):
# NOTE(jroll): pop out fields that were introduced in later API versions, # NOTE(jroll): pop out fields that were introduced in later API versions,
# unless explicitly requested. Otherwise, these will cause tests using # unless explicitly requested. Otherwise, these will cause tests using
# older API versions to fail. # older API versions to fail.
if 'network_interface' not in kw: for iface in drivers_base.ALL_INTERFACES:
node.pop('network_interface') name = '%s_interface' % iface
if name not in kw:
node.pop(name)
if 'resource_class' not in kw: if 'resource_class' not in kw:
node.pop('resource_class') node.pop('resource_class')

View File

@ -53,6 +53,7 @@ import sqlalchemy.exc
from ironic.common.i18n import _LE from ironic.common.i18n import _LE
from ironic.db.sqlalchemy import migration from ironic.db.sqlalchemy import migration
from ironic.db.sqlalchemy import models from ironic.db.sqlalchemy import models
from ironic.drivers import base as base_driver
from ironic.tests import base from ironic.tests import base
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -537,6 +538,15 @@ class MigrationCheckersMixin(object):
(sqlalchemy.types.Boolean, (sqlalchemy.types.Boolean,
sqlalchemy.types.Integer)) 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): def test_upgrade_and_version(self):
with patch_with_engine(self.engine): with patch_with_engine(self.engine):
self.migration_api.upgrade('head') self.migration_api.upgrade('head')

View File

@ -19,6 +19,7 @@ from oslo_utils import timeutils
from ironic.common import states from ironic.common import states
from ironic.db import api as db_api from ironic.db import api as db_api
from ironic.drivers import base as drivers_base
def get_test_ipmi_info(): def get_test_ipmi_info():
@ -214,7 +215,7 @@ def get_test_node(**kw):
fake_internal_info = { fake_internal_info = {
"private_state": "secret value" "private_state": "secret value"
} }
return { result = {
'id': kw.get('id', 123), 'id': kw.get('id', 123),
'name': kw.get('name', None), 'name': kw.get('name', None),
'uuid': kw.get('uuid', '1be26c0b-03f2-4d2e-ae87-c02d7f33c123'), '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'), 'target_raid_config': kw.get('target_raid_config'),
'tags': kw.get('tags', []), 'tags': kw.get('tags', []),
'resource_class': kw.get('resource_class'), '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): def create_test_node(**kw):
"""Create test node entry in DB and return Node DB object. """Create test node entry in DB and return Node DB object.

View File

@ -404,7 +404,7 @@ class TestObject(_LocalTest, _TestObject):
# version bump. It is md5 hash of object fields and remotable methods. # 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. # The fingerprint values should only be changed if there is a version bump.
expected_object_fingerprints = { expected_object_fingerprints = {
'Node': '1.18-37a1d39ba8a4957f505dda936ac9146b', 'Node': '1.19-e8b294016d8d5b322df813f790d092b4',
'MyObj': '1.5-4f5efe8f0fcaf182bbe1c7fe3ba858db', 'MyObj': '1.5-4f5efe8f0fcaf182bbe1c7fe3ba858db',
'Chassis': '1.3-d656e039fd8ae9f34efc232ab3980905', 'Chassis': '1.3-d656e039fd8ae9f34efc232ab3980905',
'Port': '1.6-609504503d68982a10f495659990084b', 'Port': '1.6-609504503d68982a10f495659990084b',

View File

@ -0,0 +1,4 @@
---
upgrade:
- Add database migration to add new fields corresponding to all interfaces
to the node table.