Add portgroups to support LAG interfaces - DB

Ironic should be able to provide the requisite connectivity
information to the Neutron ML2 plugin to allow drivers to
provision the top-of-rack switch for the bare metal server.
The addition of portgroups in Ironic allows the concept of
link aggregation to be handled in Ironic in order to provide
support for cases where multiple interfaces on the bare metal
server connect to switch ports of a single LAG.

This commit includes changes to:
- the DB models (extension of port model and addition of portgroup
  model)
- the DB tests

Partial-bug: #1526403
DocImpact
Co-Authored-By: Laura Moore (laura.moore@sap.com)
Co-Authored-By: Jenny Moorehead (jenny.moorehead@sap.com)
Co-Authored-By: Will Stevenson (will.stevenson@sap.com)

Change-Id: Ic028c316b0670c2d18de89111e83069f3441f476
This commit is contained in:
Om Kumar 2015-10-13 19:46:15 +05:30 committed by vsaienko
parent d54c1535ca
commit 1740ab7970
10 changed files with 663 additions and 1 deletions

View File

@ -161,6 +161,18 @@ class PortAlreadyExists(Conflict):
_msg_fmt = _("A port with UUID %(uuid)s already exists.")
class PortgroupAlreadyExists(Conflict):
_msg_fmt = _("A portgroup with UUID %(uuid)s already exists.")
class PortgroupDuplicateName(Conflict):
_msg_fmt = _("A portgroup with name %(name)s already exists.")
class PortgroupMACAlreadyExists(Conflict):
_msg_fmt = _("A portgroup with MAC address %(mac)s already exists.")
class InstanceAssociated(Conflict):
_msg_fmt = _("Instance %(instance_uuid)s is already associated with a "
"node, it cannot be associated with this other node %(node)s")
@ -255,6 +267,15 @@ class NodeNotFound(NotFound):
_msg_fmt = _("Node %(node)s could not be found.")
class PortgroupNotFound(NotFound):
_msg_fmt = _("Portgroup %(portgroup)s could not be found.")
class PortgroupNotEmpty(Invalid):
_msg_fmt = _("Cannot complete the requested action because portgroup "
"%(portgroup)s contains ports.")
class NodeAssociated(InvalidState):
_msg_fmt = _("Node %(node)s is associated with instance %(instance)s.")

View File

@ -260,6 +260,21 @@ class Connection(object):
:returns: A list of ports.
"""
@abc.abstractmethod
def get_ports_by_portgroup_id(self, portgroup_id, limit=None, marker=None,
sort_key=None, sort_dir=None):
"""List all the ports for a given portgroup.
:param portgroup_id: The integer portgroup ID.
:param limit: Maximum number of ports to return.
:param marker: The last item of the previous page; we return the next
result set.
:param sort_key: Attribute by which results should be sorted
:param sort_dir: Direction in which results should be sorted
(asc, desc)
:returns: A list of ports.
"""
@abc.abstractmethod
def create_port(self, values):
"""Create a new port.
@ -283,6 +298,120 @@ class Connection(object):
:param port_id: The id or MAC of a port.
"""
@abc.abstractmethod
def get_portgroup_by_id(self, portgroup_id):
"""Return a network portgroup representation.
:param portgroup_id: The id of a portgroup.
:returns: A portgroup.
:raises: PortgroupNotFound
"""
@abc.abstractmethod
def get_portgroup_by_uuid(self, portgroup_uuid):
"""Return a network portgroup representation.
:param portgroup_uuid: The uuid of a portgroup.
:returns: A portgroup.
:raises: PortgroupNotFound
"""
@abc.abstractmethod
def get_portgroup_by_address(self, address):
"""Return a network portgroup representation.
:param address: The MAC address of a portgroup.
:returns: A portgroup.
:raises: PortgroupNotFound
"""
@abc.abstractmethod
def get_portgroup_by_name(self, name):
"""Return a network portgroup representation.
:param name: The logical name of a portgroup.
:returns: A portgroup.
:raises: PortgroupNotFound
"""
@abc.abstractmethod
def get_portgroup_list(self, limit=None, marker=None,
sort_key=None, sort_dir=None):
"""Return a list of portgroups.
:param limit: Maximum number of portgroups to return.
:param marker: The last item of the previous page; we return the next
result set.
:param sort_key: Attribute by which results should be sorted.
:param sort_dir: Direction in which results should be sorted.
(asc, desc)
:returns: A list of portgroups.
"""
@abc.abstractmethod
def get_portgroups_by_node_id(self, node_id, limit=None, marker=None,
sort_key=None, sort_dir=None):
"""List all the portgroups for a given node.
:param node_id: The integer node ID.
:param limit: Maximum number of portgroups to return.
:param marker: The last item of the previous page; we return the next
result set.
:param sort_key: Attribute by which results should be sorted
:param sort_dir: Direction in which results should be sorted
(asc, desc)
:returns: A list of portgroups.
"""
@abc.abstractmethod
def create_portgroup(self, values):
"""Create a new portgroup.
:param values: Dict of values with the the following keys:
'id'
'uuid'
'name'
'node_id'
'address'
'extra'
'created_at'
'updated_at'
:returns: A portgroup
:raises: PortgroupDuplicateName
:raises: PortgroupMACAlreadyExists
:raises: PortgroupAlreadyExists
"""
@abc.abstractmethod
def update_portgroup(self, portgroup_id, values):
"""Update properties of a portgroup.
:param portgroup_id: The UUID or MAC of a portgroup.
:param values: Dict of values to update.
May contain the following keys:
'uuid'
'name'
'node_id'
'address'
'extra'
'created_at'
'updated_at'
:returns: A portgroup.
:raises: InvalidParameterValue
:raises: PortgroupNotFound
:raises: PortgroupDuplicateName
:raises: PortgroupMACAlreadyExists
"""
@abc.abstractmethod
def destroy_portgroup(self, portgroup_id):
"""Destroy a portgroup.
:param portgroup_id: The UUID or MAC of a portgroup.
:raises: PortgroupNotEmpty
:raises: PortgroupNotFound
"""
@abc.abstractmethod
def create_chassis(self, values):
"""Create a new chassis.

View File

@ -0,0 +1,54 @@
# 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.
"""Added portgroups table and altered ports
Revision ID: 5ea1b0d310e
Revises: 48d6c242bb9b
Create Date: 2015-06-30 14:14:26.972368
"""
# revision identifiers, used by Alembic.
revision = '5ea1b0d310e'
down_revision = '48d6c242bb9b'
from alembic import op
import sqlalchemy as sa
def upgrade():
op.create_table('portgroups',
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.Column('updated_at', sa.DateTime(), nullable=True),
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('uuid', sa.String(length=36), nullable=True),
sa.Column('name', sa.String(length=255), nullable=True),
sa.Column('node_id', sa.Integer(), nullable=True),
sa.Column('address', sa.String(length=18), nullable=True),
sa.Column('extra', sa.Text(), nullable=True),
sa.ForeignKeyConstraint(['node_id'], ['nodes.id'], ),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('uuid', name='uniq_portgroups0uuid'),
sa.UniqueConstraint('address',
name='uniq_portgroups0address'),
sa.UniqueConstraint('name', name='uniq_portgroups0name'),
mysql_ENGINE='InnoDB',
mysql_DEFAULT_CHARSET='UTF8')
op.add_column(u'ports', sa.Column('local_link_connection', sa.Text(),
nullable=True))
op.add_column(u'ports', sa.Column('portgroup_id', sa.Integer(),
nullable=True))
op.add_column(u'ports', sa.Column('pxe_enabled', sa.Boolean(),
default=True))
op.create_foreign_key('fk_portgroups_ports', 'ports', 'portgroups',
['portgroup_id'], ['id'])

View File

@ -117,6 +117,40 @@ def add_port_filter_by_node(query, value):
return query.filter(models.Node.uuid == value)
def add_portgroup_filter(query, value):
"""Adds a portgroup-specific filter to a query.
Filters results by address, if supplied value is a valid MAC
address. Otherwise attempts to filter results by identity.
:param query: Initial query to add filter to.
:param value: Value for filtering results by.
:return: Modified query.
"""
if utils.is_valid_mac(value):
return query.filter_by(address=value)
else:
return add_identity_filter(query, value)
def add_portgroup_filter_by_node(query, value):
if strutils.is_int_like(value):
return query.filter_by(node_id=value)
else:
query = query.join(models.Node,
models.Portgroup.node_id == models.Node.id)
return query.filter(models.Node.uuid == value)
def add_port_filter_by_portgroup(query, value):
if strutils.is_int_like(value):
return query.filter_by(portgroup_id=value)
else:
query = query.join(models.Portgroup,
models.Port.portgroup_id == models.Portgroup.id)
return query.filter(models.Portgroup.uuid == value)
def add_node_filter_by_chassis(query, value):
if strutils.is_int_like(value):
return query.filter_by(chassis_id=value)
@ -325,6 +359,11 @@ class Connection(api.Connection):
port_query = add_port_filter_by_node(port_query, node_id)
port_query.delete()
portgroup_query = model_query(models.Portgroup)
portgroup_query = add_portgroup_filter_by_node(portgroup_query,
node_id)
portgroup_query.delete()
query.delete()
def update_node(self, node_id, values):
@ -410,6 +449,13 @@ class Connection(api.Connection):
return _paginate_query(models.Port, limit, marker,
sort_key, sort_dir, query)
def get_ports_by_portgroup_id(self, portgroup_id, limit=None, marker=None,
sort_key=None, sort_dir=None):
query = model_query(models.Port)
query = query.filter_by(portgroup_id=portgroup_id)
return _paginate_query(models.Port, limit, marker,
sort_key, sort_dir, query)
def create_port(self, values):
if not values.get('uuid'):
values['uuid'] = uuidutils.generate_uuid()
@ -453,6 +499,109 @@ class Connection(api.Connection):
if count == 0:
raise exception.PortNotFound(port=port_id)
def get_portgroup_by_id(self, portgroup_id):
query = model_query(models.Portgroup).filter_by(id=portgroup_id)
try:
return query.one()
except NoResultFound:
raise exception.PortgroupNotFound(portgroup=portgroup_id)
def get_portgroup_by_uuid(self, portgroup_uuid):
query = model_query(models.Portgroup).filter_by(uuid=portgroup_uuid)
try:
return query.one()
except NoResultFound:
raise exception.PortgroupNotFound(portgroup=portgroup_uuid)
def get_portgroup_by_address(self, address):
query = model_query(models.Portgroup).filter_by(address=address)
try:
return query.one()
except NoResultFound:
raise exception.PortgroupNotFound(portgroup=address)
def get_portgroup_by_name(self, name):
query = model_query(models.Portgroup).filter_by(name=name)
try:
return query.one()
except NoResultFound:
raise exception.PortgroupNotFound(portgroup=name)
def get_portgroup_list(self, limit=None, marker=None,
sort_key=None, sort_dir=None):
return _paginate_query(models.Portgroup, limit, marker,
sort_key, sort_dir)
def get_portgroups_by_node_id(self, node_id, limit=None, marker=None,
sort_key=None, sort_dir=None):
query = model_query(models.Portgroup)
query = query.filter_by(node_id=node_id)
return _paginate_query(models.Portgroup, limit, marker,
sort_key, sort_dir, query)
def create_portgroup(self, values):
if not values.get('uuid'):
values['uuid'] = uuidutils.generate_uuid()
portgroup = models.Portgroup()
portgroup.update(values)
with _session_for_write() as session:
try:
session.add(portgroup)
session.flush()
except db_exc.DBDuplicateEntry as exc:
if 'name' in exc.columns:
raise exception.PortgroupDuplicateName(name=values['name'])
elif 'address' in exc.columns:
raise exception.PortgroupMACAlreadyExists(
mac=values['address'])
raise exception.PortgroupAlreadyExists(uuid=values['uuid'])
return portgroup
def update_portgroup(self, portgroup_id, values):
if 'uuid' in values:
msg = _("Cannot overwrite UUID for an existing portgroup.")
raise exception.InvalidParameterValue(err=msg)
with _session_for_write() as session:
try:
query = model_query(models.Portgroup)
query = add_portgroup_filter(query, portgroup_id)
ref = query.one()
ref.update(values)
session.flush()
except NoResultFound:
raise exception.PortgroupNotFound(portgroup=portgroup_id)
except db_exc.DBDuplicateEntry as exc:
if 'name' in exc.columns:
raise exception.PortgroupDuplicateName(name=values['name'])
elif 'address' in exc.columns:
raise exception.PortgroupMACAlreadyExists(
mac=values['address'])
else:
raise exc
return ref
def destroy_portgroup(self, portgroup_id):
def portgroup_not_empty(session):
"""Checks whether the portgroup does not have ports."""
query = model_query(models.Port)
query = add_port_filter_by_portgroup(query, portgroup_id)
return query.count() != 0
with _session_for_write() as session:
if portgroup_not_empty(session):
raise exception.PortgroupNotEmpty(portgroup=portgroup_id)
query = model_query(models.Portgroup, session=session)
query = add_identity_filter(query, portgroup_id)
count = query.delete()
if count == 0:
raise exception.PortgroupNotFound(portgroup=portgroup_id)
def get_chassis_by_id(self, chassis_id):
query = model_query(models.Chassis).filter_by(id=chassis_id)
try:

View File

@ -165,6 +165,26 @@ class Port(Base):
address = Column(String(18))
node_id = Column(Integer, ForeignKey('nodes.id'), nullable=True)
extra = Column(db_types.JsonEncodedDict)
local_link_connection = Column(db_types.JsonEncodedDict)
portgroup_id = Column(Integer, ForeignKey('portgroups.id'), nullable=True)
pxe_enabled = Column(Boolean, default=True)
class Portgroup(Base):
"""Represents a group of network ports of a bare metal node."""
__tablename__ = 'portgroups'
__table_args__ = (
schema.UniqueConstraint('uuid', name='uniq_portgroups0uuid'),
schema.UniqueConstraint('address', name='uniq_portgroups0address'),
schema.UniqueConstraint('name', name='uniq_portgroups0name'),
table_args())
id = Column(Integer, primary_key=True)
uuid = Column(String(36))
name = Column(String(255), nullable=True)
node_id = Column(Integer, ForeignKey('nodes.id'), nullable=True)
address = Column(String(18))
extra = Column(db_types.JsonEncodedDict)
class NodeTag(Base):

View File

@ -103,6 +103,11 @@ def port_post_data(**kw):
port = utils.get_test_port(**kw)
# node_id is not part of the API object
port.pop('node_id')
# TODO(vsaienko): remove when API part is added
port.pop('local_link_connection')
port.pop('pxe_enabled')
# portgroup_id is not part of the API object
port.pop('portgroup_id')
internal = port_controller.PortPatchType.internal_attrs()
return remove_internal(port, internal)

View File

@ -407,6 +407,43 @@ class MigrationCheckersMixin(object):
tag = node_tags.select(node_tags.c.node_id == '123').execute().first()
self.assertEqual('tag1', tag['tag'])
def _check_5ea1b0d310e(self, engine, data):
portgroup = db_utils.get_table(engine, 'portgroups')
col_names = [column.name for column in portgroup.c]
expected_names = ['created_at', 'updated_at', 'id', 'uuid', 'name',
'node_id', 'address', 'extra']
self.assertEqual(sorted(expected_names), sorted(col_names))
self.assertIsInstance(portgroup.c.created_at.type,
sqlalchemy.types.DateTime)
self.assertIsInstance(portgroup.c.updated_at.type,
sqlalchemy.types.DateTime)
self.assertIsInstance(portgroup.c.id.type,
sqlalchemy.types.Integer)
self.assertIsInstance(portgroup.c.uuid.type,
sqlalchemy.types.String)
self.assertIsInstance(portgroup.c.name.type,
sqlalchemy.types.String)
self.assertIsInstance(portgroup.c.node_id.type,
sqlalchemy.types.Integer)
self.assertIsInstance(portgroup.c.address.type,
sqlalchemy.types.String)
self.assertIsInstance(portgroup.c.extra.type,
sqlalchemy.types.TEXT)
ports = db_utils.get_table(engine, 'ports')
col_names = [column.name for column in ports.c]
self.assertIn('pxe_enabled', col_names)
self.assertIn('portgroup_id', col_names)
self.assertIn('local_link_connection', col_names)
self.assertIsInstance(ports.c.portgroup_id.type,
sqlalchemy.types.Integer)
# in some backends bool type is integer
self.assertTrue(isinstance(ports.c.pxe_enabled.type,
sqlalchemy.types.Boolean) or
isinstance(ports.c.pxe_enabled.type,
sqlalchemy.types.Integer))
def test_upgrade_and_version(self):
with patch_with_engine(self.engine):
self.migration_api.upgrade('head')

View File

@ -0,0 +1,202 @@
# 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.
"""Tests for manipulating portgroups via the DB API"""
from oslo_utils import uuidutils
import six
from ironic.common import exception
from ironic.tests.unit.db import base
from ironic.tests.unit.db import utils as db_utils
class DbportgroupTestCase(base.DbTestCase):
def setUp(self):
# This method creates a portgroup for every test and
# replaces a test for creating a portgroup.
super(DbportgroupTestCase, self).setUp()
self.node = db_utils.create_test_node()
self.portgroup = db_utils.create_test_portgroup(node_id=self.node.id)
def _create_test_portgroup_range(self, count):
"""Create the specified number of test portgroup entries in DB
It uses create_test_portgroup method. And returns List of Portgroup
DB objects.
:param count: Specifies the number of portgroups to be created
:returns: List of Portgroup DB objects
"""
uuids = []
for i in range(1, count):
portgroup = db_utils.create_test_portgroup(
uuid=uuidutils.generate_uuid(),
name='portgroup' + str(i),
address='52:54:00:cf:2d:4%s' % i)
uuids.append(six.text_type(portgroup.uuid))
return uuids
def test_get_portgroup_by_id(self):
res = self.dbapi.get_portgroup_by_id(self.portgroup.id)
self.assertEqual(self.portgroup.address, res.address)
def test_get_portgroup_by_id_that_does_not_exist(self):
self.assertRaises(exception.PortgroupNotFound,
self.dbapi.get_portgroup_by_id, 99)
def test_get_portgroup_by_uuid(self):
res = self.dbapi.get_portgroup_by_uuid(self.portgroup.uuid)
self.assertEqual(self.portgroup.id, res.id)
def test_get_portgroup_by_uuid_that_does_not_exist(self):
self.assertRaises(exception.PortgroupNotFound,
self.dbapi.get_portgroup_by_uuid,
'EEEEEEEE-EEEE-EEEE-EEEE-EEEEEEEEEEEE')
def test_get_portgroup_by_address(self):
res = self.dbapi.get_portgroup_by_address(self.portgroup.address)
self.assertEqual(self.portgroup.id, res.id)
def test_get_portgroup_by_address_that_does_not_exist(self):
self.assertRaises(exception.PortgroupNotFound,
self.dbapi.get_portgroup_by_address,
'31:31:31:31:31:31')
def test_get_portgroup_by_name(self):
res = self.dbapi.get_portgroup_by_name(self.portgroup.name)
self.assertEqual(self.portgroup.id, res.id)
def test_get_portgroup_by_name_that_does_not_exist(self):
self.assertRaises(exception.PortgroupNotFound,
self.dbapi.get_portgroup_by_name, 'testfail')
def test_get_portgroup_list(self):
uuids = self._create_test_portgroup_range(6)
# Also add the uuid for the portgroup created in setUp()
uuids.append(six.text_type(self.portgroup.uuid))
res = self.dbapi.get_portgroup_list()
res_uuids = [r.uuid for r in res]
six.assertCountEqual(self, uuids, res_uuids)
def test_get_portgroup_list_sorted(self):
uuids = self._create_test_portgroup_range(6)
# Also add the uuid for the portgroup created in setUp()
uuids.append(six.text_type(self.portgroup.uuid))
res = self.dbapi.get_portgroup_list(sort_key='uuid')
res_uuids = [r.uuid for r in res]
self.assertEqual(sorted(uuids), res_uuids)
self.assertRaises(exception.InvalidParameterValue,
self.dbapi.get_portgroup_list, sort_key='foo')
def test_get_portgroups_by_node_id(self):
res = self.dbapi.get_portgroups_by_node_id(self.node.id)
self.assertEqual(self.portgroup.address, res[0].address)
def test_get_portgroups_by_node_id_that_does_not_exist(self):
self.assertEqual([], self.dbapi.get_portgroups_by_node_id(99))
def test_destroy_portgroup(self):
self.dbapi.destroy_portgroup(self.portgroup.id)
self.assertRaises(exception.PortgroupNotFound,
self.dbapi.get_portgroup_by_id, self.portgroup.id)
def test_destroy_portgroup_that_does_not_exist(self):
self.assertRaises(exception.PortgroupNotFound,
self.dbapi.destroy_portgroup, 99)
def test_destroy_portgroup_uuid(self):
self.dbapi.destroy_portgroup(self.portgroup.uuid)
def test_destroy_portgroup_not_empty(self):
self.port = db_utils.create_test_port(node_id=self.node.id,
portgroup_id=self.portgroup.id)
self.assertRaises(exception.PortgroupNotEmpty,
self.dbapi.destroy_portgroup, self.portgroup.id)
def test_update_portgroup(self):
old_address = self.portgroup.address
new_address = 'ff:ee:dd:cc:bb:aa'
self.assertNotEqual(old_address, new_address)
old_name = self.portgroup.name
new_name = 'newname'
self.assertNotEqual(old_name, new_name)
res = self.dbapi.update_portgroup(self.portgroup.id,
{'address': new_address,
'name': new_name})
self.assertEqual(new_address, res.address)
self.assertEqual(new_name, res.name)
def test_update_portgroup_uuid(self):
self.assertRaises(exception.InvalidParameterValue,
self.dbapi.update_portgroup, self.portgroup.id,
{'uuid': ''})
def test_update_portgroup_not_found(self):
id_2 = 99
self.assertNotEqual(self.portgroup.id, id_2)
address2 = 'aa:bb:cc:11:22:33'
self.assertRaises(exception.PortgroupNotFound,
self.dbapi.update_portgroup, id_2,
{'address': address2})
def test_update_portgroup_duplicated_address(self):
address1 = self.portgroup.address
address2 = 'aa:bb:cc:11:22:33'
portgroup2 = db_utils.create_test_portgroup(
uuid=uuidutils.generate_uuid(),
node_id=self.node.id,
name=str(uuidutils.generate_uuid()),
address=address2)
self.assertRaises(exception.PortgroupMACAlreadyExists,
self.dbapi.update_portgroup, portgroup2.id,
{'address': address1})
def test_update_portgroup_duplicated_name(self):
name1 = self.portgroup.name
portgroup2 = db_utils.create_test_portgroup(
uuid=uuidutils.generate_uuid(),
node_id=self.node.id,
name='name2', address='aa:bb:cc:11:22:55')
self.assertRaises(exception.PortgroupDuplicateName,
self.dbapi.update_portgroup, portgroup2.id,
{'name': name1})
def test_create_portgroup_duplicated_name(self):
self.assertRaises(exception.PortgroupDuplicateName,
db_utils.create_test_portgroup,
uuid=uuidutils.generate_uuid(),
node_id=self.node.id,
name=self.portgroup.name,
address='aa:bb:cc:11:22:55')
def test_create_portgroup_duplicated_address(self):
self.assertRaises(exception.PortgroupMACAlreadyExists,
db_utils.create_test_portgroup,
uuid=uuidutils.generate_uuid(),
node_id=self.node.id,
name=str(uuidutils.generate_uuid()),
address=self.portgroup.address)
def test_create_portgroup_duplicated_uuid(self):
self.assertRaises(exception.PortgroupAlreadyExists,
db_utils.create_test_portgroup,
uuid=self.portgroup.uuid,
node_id=self.node.id,
name=str(uuidutils.generate_uuid()),
address='aa:bb:cc:33:11:22')

View File

@ -30,7 +30,9 @@ class DbPortTestCase(base.DbTestCase):
# replaces a test for creating a port.
super(DbPortTestCase, self).setUp()
self.node = db_utils.create_test_node()
self.port = db_utils.create_test_port(node_id=self.node.id)
self.portgroup = db_utils.create_test_portgroup(node_id=self.node.id)
self.port = db_utils.create_test_port(node_id=self.node.id,
portgroup_id=self.portgroup.id)
def test_get_port_by_id(self):
res = self.dbapi.get_port_by_id(self.port.id)
@ -78,6 +80,13 @@ class DbPortTestCase(base.DbTestCase):
def test_get_ports_by_node_id_that_does_not_exist(self):
self.assertEqual([], self.dbapi.get_ports_by_node_id(99))
def test_get_ports_by_portgroup_id(self):
res = self.dbapi.get_ports_by_portgroup_id(self.portgroup.id)
self.assertEqual(self.port.address, res[0].address)
def test_get_ports_by_portgroup_id_that_does_not_exist(self):
self.assertEqual([], self.dbapi.get_ports_by_portgroup_id(99))
def test_destroy_port(self):
self.dbapi.destroy_port(self.port.id)
self.assertRaises(exception.PortNotFound,

View File

@ -253,6 +253,12 @@ def get_test_port(**kw):
'extra': kw.get('extra', {}),
'created_at': kw.get('created_at'),
'updated_at': kw.get('updated_at'),
'local_link_connection': kw.get('local_link_connection',
{'switch_id': '0a:1b:2c:3d:4e:5f',
'port_id': 'Ethernet3/1',
'switch_info': 'switch1'}),
'portgroup_id': kw.get('portgroup_id'),
'pxe_enabled': kw.get('pxe_enabled', True),
}
@ -344,3 +350,33 @@ def get_test_oneview_driver_info():
return {
'server_hardware_uri': 'fake_sh_uri',
}
def get_test_portgroup(**kw):
return {
'id': kw.get('id', 654),
'uuid': kw.get('uuid', '6eb02b44-18a3-4659-8c0b-8d2802581ae4'),
'name': kw.get('name', 'fooname'),
'node_id': kw.get('node_id', 123),
'address': kw.get('address', '52:54:00:cf:2d:31'),
'extra': kw.get('extra', {}),
'created_at': kw.get('created_at'),
'updated_at': kw.get('updated_at'),
}
def create_test_portgroup(**kw):
"""Create test portgroup entry in DB and return Portgroup DB object.
Function to be used to create test Portgroup objects in the database.
:param kw: kwargs with overriding values for port's attributes.
:returns: Test Portgroup DB object.
"""
portgroup = get_test_portgroup(**kw)
# Let DB generate ID if it isn't specified explicitly
if 'id' not in kw:
del portgroup['id']
dbapi = db_api.get_instance()
return dbapi.create_portgroup(portgroup)