Merge "Add portgroups to support LAG interfaces - objs"
This commit is contained in:
@@ -28,3 +28,4 @@ def register_all():
|
||||
__import__('ironic.objects.conductor')
|
||||
__import__('ironic.objects.node')
|
||||
__import__('ironic.objects.port')
|
||||
__import__('ironic.objects.portgroup')
|
||||
|
||||
+32
-1
@@ -32,7 +32,9 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
|
||||
# Version 1.2: Add create() and destroy()
|
||||
# Version 1.3: Add list()
|
||||
# Version 1.4: Add list_by_node_id()
|
||||
VERSION = '1.4'
|
||||
# Version 1.5: Add list_by_portgroup_id() and new fields
|
||||
# local_link_connection, portgroup_id and pxe_enabled
|
||||
VERSION = '1.5'
|
||||
|
||||
dbapi = dbapi.get_instance()
|
||||
|
||||
@@ -42,6 +44,10 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
|
||||
'node_id': object_fields.IntegerField(nullable=True),
|
||||
'address': object_fields.MACAddressField(nullable=True),
|
||||
'extra': object_fields.FlexibleDictField(nullable=True),
|
||||
'local_link_connection': object_fields.FlexibleDictField(
|
||||
nullable=True),
|
||||
'portgroup_id': object_fields.IntegerField(nullable=True),
|
||||
'pxe_enabled': object_fields.BooleanField()
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
@@ -184,6 +190,31 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
|
||||
sort_dir=sort_dir)
|
||||
return Port._from_db_object_list(db_ports, cls, context)
|
||||
|
||||
# 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.
|
||||
# @object_base.remotable_classmethod
|
||||
@classmethod
|
||||
def list_by_portgroup_id(cls, context, portgroup_id, limit=None,
|
||||
marker=None, sort_key=None, sort_dir=None):
|
||||
"""Return a list of Port objects associated with a given portgroup ID.
|
||||
|
||||
:param context: Security context.
|
||||
:param portgroup_id: the ID of the portgroup.
|
||||
:param limit: maximum number of resources to return in a single result.
|
||||
:param marker: pagination marker for large data sets.
|
||||
:param sort_key: column to sort results by.
|
||||
:param sort_dir: direction to sort. "asc" or "desc".
|
||||
:returns: a list of :class:`Port` object.
|
||||
|
||||
"""
|
||||
db_ports = cls.dbapi.get_ports_by_portgroup_id(portgroup_id,
|
||||
limit=limit,
|
||||
marker=marker,
|
||||
sort_key=sort_key,
|
||||
sort_dir=sort_dir)
|
||||
return Port._from_db_object_list(db_ports, cls, context)
|
||||
|
||||
# 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.
|
||||
|
||||
@@ -0,0 +1,288 @@
|
||||
# coding=utf-8
|
||||
#
|
||||
#
|
||||
# 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.
|
||||
|
||||
from oslo_utils import strutils
|
||||
from oslo_utils import uuidutils
|
||||
from oslo_versionedobjects import base as object_base
|
||||
|
||||
from ironic.common import exception
|
||||
from ironic.common import utils
|
||||
from ironic.db import api as dbapi
|
||||
from ironic.objects import base
|
||||
from ironic.objects import fields as object_fields
|
||||
|
||||
|
||||
@base.IronicObjectRegistry.register
|
||||
class Portgroup(base.IronicObject, object_base.VersionedObjectDictCompat):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
dbapi = dbapi.get_instance()
|
||||
|
||||
fields = {
|
||||
'id': object_fields.IntegerField(),
|
||||
'uuid': object_fields.UUIDField(nullable=True),
|
||||
'name': object_fields.StringField(nullable=True),
|
||||
'node_id': object_fields.IntegerField(nullable=True),
|
||||
'address': object_fields.MACAddressField(nullable=True),
|
||||
'extra': object_fields.FlexibleDictField(nullable=True),
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _from_db_object(portgroup, db_portgroup):
|
||||
"""Converts a database entity to a formal object."""
|
||||
for field in portgroup.fields:
|
||||
portgroup[field] = db_portgroup[field]
|
||||
|
||||
portgroup.obj_reset_changes()
|
||||
return portgroup
|
||||
|
||||
@staticmethod
|
||||
def _from_db_object_list(db_objects, cls, context):
|
||||
"""Converts a list of database entities to a list of formal objects."""
|
||||
return [Portgroup._from_db_object(cls(context), obj) for obj in
|
||||
db_objects]
|
||||
|
||||
# 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.
|
||||
# @object_base.remotable_classmethod
|
||||
@classmethod
|
||||
def get(cls, context, portgroup_ident):
|
||||
"""Find a portgroup based on its id, uuid, name or address.
|
||||
|
||||
:param portgroup_ident: The id, uuid, name or address of a portgroup.
|
||||
:param context: Security context
|
||||
:returns: A :class:`Portgroup` object.
|
||||
:raises: InvalidIdentity
|
||||
|
||||
"""
|
||||
if strutils.is_int_like(portgroup_ident):
|
||||
return cls.get_by_id(context, portgroup_ident)
|
||||
elif uuidutils.is_uuid_like(portgroup_ident):
|
||||
return cls.get_by_uuid(context, portgroup_ident)
|
||||
elif utils.is_valid_mac(portgroup_ident):
|
||||
return cls.get_by_address(context, portgroup_ident)
|
||||
elif utils.is_valid_logical_name(portgroup_ident):
|
||||
return cls.get_by_name(context, portgroup_ident)
|
||||
else:
|
||||
raise exception.InvalidIdentity(identity=portgroup_ident)
|
||||
|
||||
# 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.
|
||||
# @object_base.remotable_classmethod
|
||||
@classmethod
|
||||
def get_by_id(cls, context, portgroup_id):
|
||||
"""Find a portgroup based on its integer id and return a Portgroup object.
|
||||
|
||||
:param portgroup id: The id of a portgroup.
|
||||
:param context: Security context
|
||||
:returns: A :class:`Portgroup` object.
|
||||
:raises: PortgroupNotFound
|
||||
|
||||
"""
|
||||
db_portgroup = cls.dbapi.get_portgroup_by_id(portgroup_id)
|
||||
portgroup = Portgroup._from_db_object(cls(context), db_portgroup)
|
||||
return portgroup
|
||||
|
||||
# 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.
|
||||
# @object_base.remotable_classmethod
|
||||
@classmethod
|
||||
def get_by_uuid(cls, context, uuid):
|
||||
"""Find a portgroup based on uuid and return a :class:`Portgroup` object.
|
||||
|
||||
:param uuid: The uuid of a portgroup.
|
||||
:param context: Security context
|
||||
:returns: A :class:`Portgroup` object.
|
||||
:raises: PortgroupNotFound
|
||||
|
||||
"""
|
||||
db_portgroup = cls.dbapi.get_portgroup_by_uuid(uuid)
|
||||
portgroup = Portgroup._from_db_object(cls(context), db_portgroup)
|
||||
return portgroup
|
||||
|
||||
# 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.
|
||||
# @object_base.remotable_classmethod
|
||||
@classmethod
|
||||
def get_by_address(cls, context, address):
|
||||
"""Find a portgroup based on address and return a :class:`Portgroup` object.
|
||||
|
||||
:param address: The MAC address of a portgroup.
|
||||
:param context: Security context
|
||||
:returns: A :class:`Portgroup` object.
|
||||
:raises: PortgroupNotFound
|
||||
|
||||
"""
|
||||
db_portgroup = cls.dbapi.get_portgroup_by_address(address)
|
||||
portgroup = Portgroup._from_db_object(cls(context), db_portgroup)
|
||||
return portgroup
|
||||
|
||||
# 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.
|
||||
# @object_base.remotable_classmethod
|
||||
@classmethod
|
||||
def get_by_name(cls, context, name):
|
||||
"""Find a portgroup based on name and return a :class:`Portgroup` object.
|
||||
|
||||
:param name: The name of a portgroup.
|
||||
:param context: Security context
|
||||
:returns: A :class:`Portgroup` object.
|
||||
:raises: PortgroupNotFound
|
||||
|
||||
"""
|
||||
db_portgroup = cls.dbapi.get_portgroup_by_name(name)
|
||||
portgroup = Portgroup._from_db_object(cls(context), db_portgroup)
|
||||
return portgroup
|
||||
|
||||
# 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.
|
||||
# @object_base.remotable_classmethod
|
||||
@classmethod
|
||||
def list(cls, context, limit=None, marker=None,
|
||||
sort_key=None, sort_dir=None):
|
||||
"""Return a list of Portgroup objects.
|
||||
|
||||
:param context: Security context.
|
||||
:param limit: Maximum number of resources to return in a single result.
|
||||
:param marker: Pagination marker for large data sets.
|
||||
:param sort_key: Column to sort results by.
|
||||
:param sort_dir: Direction to sort. "asc" or "desc".
|
||||
:returns: A list of :class:`Portgroup` object.
|
||||
:raises: InvalidParameterValue
|
||||
|
||||
"""
|
||||
db_portgroups = cls.dbapi.get_portgroup_list(limit=limit,
|
||||
marker=marker,
|
||||
sort_key=sort_key,
|
||||
sort_dir=sort_dir)
|
||||
return Portgroup._from_db_object_list(db_portgroups, cls, context)
|
||||
|
||||
# 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.
|
||||
# @object_base.remotable_classmethod
|
||||
@classmethod
|
||||
def list_by_node_id(cls, context, node_id, limit=None, marker=None,
|
||||
sort_key=None, sort_dir=None):
|
||||
"""Return a list of Portgroup objects associated with a given node ID.
|
||||
|
||||
:param context: Security context.
|
||||
:param node_id: The ID of the node.
|
||||
:param limit: Maximum number of resources to return in a single result.
|
||||
:param marker: Pagination marker for large data sets.
|
||||
:param sort_key: Column to sort results by.
|
||||
:param sort_dir: Direction to sort. "asc" or "desc".
|
||||
:returns: A list of :class:`Portgroup` object.
|
||||
:raises: InvalidParameterValue
|
||||
|
||||
"""
|
||||
db_portgroups = cls.dbapi.get_portgroups_by_node_id(node_id,
|
||||
limit=limit,
|
||||
marker=marker,
|
||||
sort_key=sort_key,
|
||||
sort_dir=sort_dir)
|
||||
return Portgroup._from_db_object_list(db_portgroups, cls, context)
|
||||
|
||||
# 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.
|
||||
# @object_base.remotable
|
||||
def create(self, context=None):
|
||||
"""Create a Portgroup record in the DB.
|
||||
|
||||
:param context: Security context. NOTE: This should only
|
||||
be used internally by the indirection_api.
|
||||
Unfortunately, RPC requires context as the first
|
||||
argument, even though we don't use it.
|
||||
A context should be set when instantiating the
|
||||
object, e.g.: Portgroup(context)
|
||||
:raises: DuplicateName, MACAlreadyExists, PortgroupAlreadyExists
|
||||
|
||||
"""
|
||||
values = self.obj_get_changes()
|
||||
db_portgroup = self.dbapi.create_portgroup(values)
|
||||
self._from_db_object(self, db_portgroup)
|
||||
|
||||
# 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.
|
||||
# @object_base.remotable
|
||||
def destroy(self, context=None):
|
||||
"""Delete the Portgroup from the DB.
|
||||
|
||||
:param context: Security context. NOTE: This should only
|
||||
be used internally by the indirection_api.
|
||||
Unfortunately, RPC requires context as the first
|
||||
argument, even though we don't use it.
|
||||
A context should be set when instantiating the
|
||||
object, e.g.: Portgroup(context)
|
||||
:raises: PortgroupNotEmpty, PortgroupNotFound
|
||||
|
||||
"""
|
||||
self.dbapi.destroy_portgroup(self.uuid)
|
||||
self.obj_reset_changes()
|
||||
|
||||
# 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.
|
||||
# @object_base.remotable
|
||||
def save(self, context=None):
|
||||
"""Save updates to this Portgroup.
|
||||
|
||||
Updates will be made column by column based on the result
|
||||
of self.what_changed().
|
||||
|
||||
:param context: Security context. NOTE: This should only
|
||||
be used internally by the indirection_api.
|
||||
Unfortunately, RPC requires context as the first
|
||||
argument, even though we don't use it.
|
||||
A context should be set when instantiating the
|
||||
object, e.g.: Portgroup(context)
|
||||
:raises: PortgroupNotFound, DuplicateName, MACAlreadyExists
|
||||
|
||||
"""
|
||||
updates = self.obj_get_changes()
|
||||
updated_portgroup = self.dbapi.update_portgroup(self.uuid, updates)
|
||||
self._from_db_object(self, updated_portgroup)
|
||||
|
||||
# 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.
|
||||
# @object_base.remotable
|
||||
def refresh(self, context=None):
|
||||
"""Loads updates for this Portgroup.
|
||||
|
||||
Loads a portgroup with the same uuid from the database and
|
||||
checks for updated attributes. Updates are applied from
|
||||
the loaded portgroup column by column, if there are any updates.
|
||||
|
||||
:param context: Security context. NOTE: This should only
|
||||
be used internally by the indirection_api.
|
||||
Unfortunately, RPC requires context as the first
|
||||
argument, even though we don't use it.
|
||||
A context should be set when instantiating the
|
||||
object, e.g.: Portgroup(context)
|
||||
:raises: PortgroupNotFound
|
||||
|
||||
"""
|
||||
current = self.__class__.get_by_uuid(self._context, uuid=self.uuid)
|
||||
self.obj_refresh(current)
|
||||
@@ -407,7 +407,8 @@ expected_object_fingerprints = {
|
||||
'Node': '1.14-9ee8ab283b06398545880dfdedb49891',
|
||||
'MyObj': '1.5-4f5efe8f0fcaf182bbe1c7fe3ba858db',
|
||||
'Chassis': '1.3-d656e039fd8ae9f34efc232ab3980905',
|
||||
'Port': '1.4-f5aa3ff81d1459d6d7e6d9d9dceed351',
|
||||
'Port': '1.5-a224755c3da5bc5cf1a14a11c0d00f3f',
|
||||
'Portgroup': '1.0-1ac4db8fa31edd9e1637248ada4c25a1',
|
||||
'Conductor': '1.0-5091f249719d4a465062a1b3dc7f860d'
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
# 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.
|
||||
|
||||
import datetime
|
||||
import mock
|
||||
from testtools.matchers import HasLength
|
||||
|
||||
from ironic.common import exception
|
||||
from ironic import objects
|
||||
from ironic.tests.unit.db import base
|
||||
from ironic.tests.unit.db import utils
|
||||
|
||||
|
||||
class TestPortgroupObject(base.DbTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestPortgroupObject, self).setUp()
|
||||
self.fake_portgroup = utils.get_test_portgroup()
|
||||
|
||||
def test_get_by_id(self):
|
||||
portgroup_id = self.fake_portgroup['id']
|
||||
with mock.patch.object(self.dbapi, 'get_portgroup_by_id',
|
||||
autospec=True) as mock_get_portgroup:
|
||||
mock_get_portgroup.return_value = self.fake_portgroup
|
||||
|
||||
portgroup = objects.Portgroup.get(self.context, portgroup_id)
|
||||
|
||||
mock_get_portgroup.assert_called_once_with(portgroup_id)
|
||||
self.assertEqual(self.context, portgroup._context)
|
||||
|
||||
def test_get_by_uuid(self):
|
||||
uuid = self.fake_portgroup['uuid']
|
||||
with mock.patch.object(self.dbapi, 'get_portgroup_by_uuid',
|
||||
autospec=True) as mock_get_portgroup:
|
||||
mock_get_portgroup.return_value = self.fake_portgroup
|
||||
|
||||
portgroup = objects.Portgroup.get(self.context, uuid)
|
||||
|
||||
mock_get_portgroup.assert_called_once_with(uuid)
|
||||
self.assertEqual(self.context, portgroup._context)
|
||||
|
||||
def test_get_by_address(self):
|
||||
address = self.fake_portgroup['address']
|
||||
with mock.patch.object(self.dbapi, 'get_portgroup_by_address',
|
||||
autospec=True) as mock_get_portgroup:
|
||||
mock_get_portgroup.return_value = self.fake_portgroup
|
||||
|
||||
portgroup = objects.Portgroup.get(self.context, address)
|
||||
|
||||
mock_get_portgroup.assert_called_once_with(address)
|
||||
self.assertEqual(self.context, portgroup._context)
|
||||
|
||||
def test_get_by_name(self):
|
||||
name = self.fake_portgroup['name']
|
||||
with mock.patch.object(self.dbapi, 'get_portgroup_by_name',
|
||||
autospec=True) as mock_get_portgroup:
|
||||
mock_get_portgroup.return_value = self.fake_portgroup
|
||||
portgroup = objects.Portgroup.get(self.context, name)
|
||||
|
||||
mock_get_portgroup.assert_called_once_with(name)
|
||||
self.assertEqual(self.context, portgroup._context)
|
||||
|
||||
def test_get_bad_id_and_uuid_and_address_and_name(self):
|
||||
self.assertRaises(exception.InvalidIdentity,
|
||||
objects.Portgroup.get,
|
||||
self.context,
|
||||
'not:a_name_or_uuid')
|
||||
|
||||
def test_save(self):
|
||||
uuid = self.fake_portgroup['uuid']
|
||||
address = "b2:54:00:cf:2d:40"
|
||||
test_time = datetime.datetime(2000, 1, 1, 0, 0)
|
||||
with mock.patch.object(self.dbapi, 'get_portgroup_by_uuid',
|
||||
autospec=True) as mock_get_portgroup:
|
||||
mock_get_portgroup.return_value = self.fake_portgroup
|
||||
with mock.patch.object(self.dbapi, 'update_portgroup',
|
||||
autospec=True) as mock_update_portgroup:
|
||||
mock_update_portgroup.return_value = (
|
||||
utils.get_test_portgroup(address=address,
|
||||
updated_at=test_time))
|
||||
p = objects.Portgroup.get_by_uuid(self.context, uuid)
|
||||
p.address = address
|
||||
p.save()
|
||||
|
||||
mock_get_portgroup.assert_called_once_with(uuid)
|
||||
mock_update_portgroup.assert_called_once_with(
|
||||
uuid, {'address': "b2:54:00:cf:2d:40"})
|
||||
self.assertEqual(self.context, p._context)
|
||||
res_updated_at = (p.updated_at).replace(tzinfo=None)
|
||||
self.assertEqual(test_time, res_updated_at)
|
||||
|
||||
def test_refresh(self):
|
||||
uuid = self.fake_portgroup['uuid']
|
||||
returns = [self.fake_portgroup,
|
||||
utils.get_test_portgroup(address="c3:54:00:cf:2d:40")]
|
||||
expected = [mock.call(uuid), mock.call(uuid)]
|
||||
with mock.patch.object(self.dbapi, 'get_portgroup_by_uuid',
|
||||
side_effect=returns,
|
||||
autospec=True) as mock_get_portgroup:
|
||||
p = objects.Portgroup.get_by_uuid(self.context, uuid)
|
||||
self.assertEqual("52:54:00:cf:2d:31", p.address)
|
||||
p.refresh()
|
||||
self.assertEqual("c3:54:00:cf:2d:40", p.address)
|
||||
|
||||
self.assertEqual(expected, mock_get_portgroup.call_args_list)
|
||||
self.assertEqual(self.context, p._context)
|
||||
|
||||
def test_list(self):
|
||||
with mock.patch.object(self.dbapi, 'get_portgroup_list',
|
||||
autospec=True) as mock_get_list:
|
||||
mock_get_list.return_value = [self.fake_portgroup]
|
||||
portgroups = objects.Portgroup.list(self.context)
|
||||
self.assertThat(portgroups, HasLength(1))
|
||||
self.assertIsInstance(portgroups[0], objects.Portgroup)
|
||||
self.assertEqual(self.context, portgroups[0]._context)
|
||||
|
||||
def test_list_by_node_id(self):
|
||||
with mock.patch.object(self.dbapi, 'get_portgroups_by_node_id',
|
||||
autospec=True) as mock_get_list:
|
||||
mock_get_list.return_value = [self.fake_portgroup]
|
||||
node_id = self.fake_portgroup['node_id']
|
||||
portgroups = objects.Portgroup.list_by_node_id(self.context,
|
||||
node_id)
|
||||
self.assertThat(portgroups, HasLength(1))
|
||||
self.assertIsInstance(portgroups[0], objects.Portgroup)
|
||||
self.assertEqual(self.context, portgroups[0]._context)
|
||||
@@ -97,3 +97,30 @@ def create_test_chassis(ctxt, **kw):
|
||||
chassis = get_test_chassis(ctxt, **kw)
|
||||
chassis.create()
|
||||
return chassis
|
||||
|
||||
|
||||
def get_test_portgroup(ctxt, **kw):
|
||||
"""Return a Portgroup object with appropriate attributes.
|
||||
|
||||
NOTE: The object leaves the attributes marked as changed, such
|
||||
that a create() could be used to commit it to the DB.
|
||||
"""
|
||||
db_portgroup = db_utils.get_test_portgroup(**kw)
|
||||
# Let DB generate ID if it isn't specified explicitly
|
||||
if 'id' not in kw:
|
||||
del db_portgroup['id']
|
||||
portgroup = objects.Portgroup(ctxt)
|
||||
for key in db_portgroup:
|
||||
setattr(portgroup, key, db_portgroup[key])
|
||||
return portgroup
|
||||
|
||||
|
||||
def create_test_portgroup(ctxt, **kw):
|
||||
"""Create and return a test portgroup object.
|
||||
|
||||
Create a portgroup in the DB and return a Portgroup object with appropriate
|
||||
attributes.
|
||||
"""
|
||||
portgroup = get_test_portgroup(ctxt, **kw)
|
||||
portgroup.create()
|
||||
return portgroup
|
||||
|
||||
Reference in New Issue
Block a user