BIOS Settings: Add RPC object

Add BIOS Objects to expose DB operations to API:

* BIOSSetting
  + create
  + save
  + get
  + delete

* BIOSSettingList
  + create
  + save
  + get_by_node_id

This patch also adds BIOSSetting and BIOSSettingList
in expected_object_fingerprints.

Co-Authored-By: Yolanda Robla Mota <yroblamo@redhat.com>
Change-Id: I4901dd4ce018b84c92f4f58ef29a7fbc79851a25
Story: #1712032
This commit is contained in:
Zenghui Shi 2018-03-23 13:23:41 +08:00
parent 91251d19ad
commit 9eaff34b5b
4 changed files with 347 additions and 0 deletions

View File

@ -24,6 +24,7 @@ def register_all():
# NOTE(danms): You must make sure your object gets imported in this
# function in order for it to be registered by services that may
# need to receive it via RPC.
__import__('ironic.objects.bios')
__import__('ironic.objects.chassis')
__import__('ironic.objects.conductor')
__import__('ironic.objects.node')

195
ironic/objects/bios.py Normal file
View File

@ -0,0 +1,195 @@
# 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_versionedobjects import base as object_base
from ironic.db import api as dbapi
from ironic.objects import base
from ironic.objects import fields as object_fields
@base.IronicObjectRegistry.register
class BIOSSetting(base.IronicObject):
# Version 1.0: Initial version
VERSION = '1.0'
dbapi = dbapi.get_instance()
fields = {
'node_id': object_fields.StringField(nullable=False),
'name': object_fields.StringField(nullable=False),
'value': object_fields.StringField(nullable=True),
}
# 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 BIOS Setting record in 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.: BIOSSetting(context)
:raises: NodeNotFound if the node id is not found.
:raises: BIOSSettingAlreadyExists if the setting record already exists.
"""
values = self.do_version_changes_for_db()
setting = [{'name': values['name'], 'value': values['value']}]
db_bios_setting = self.dbapi.create_bios_setting_list(
values['node_id'], setting, values['version'])
self._from_db_object(self._context, self, db_bios_setting[0])
# 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 BIOS Setting update in 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.: BIOSSetting(context)
:raises: NodeNotFound if the node id is not found.
:raises: BIOSSettingNotFound if the bios setting name is not found.
"""
values = self.do_version_changes_for_db()
setting = [{'name': values['name'], 'value': values['value']}]
updated_bios_setting = self.dbapi.update_bios_setting_list(
values['node_id'], setting, values['version'])
self._from_db_object(self._context, self, updated_bios_setting[0])
# 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, node_id, name):
"""Get a BIOS Setting based on its node_id and name.
:param context: Security context.
:param node_id: The node id.
:param name: Bios setting name to be retrieved.
:raises: NodeNotFound if the node id is not found.
:raises: BIOSSettingNotFound if the bios setting name is not found.
:returns: A :class:'BIOSSetting' object.
"""
db_bios_setting = cls.dbapi.get_bios_setting(node_id, name)
return cls._from_db_object(context, cls(), db_bios_setting)
# 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 delete(cls, context, node_id, name):
"""Delete a BIOS Setting based on its node_id and name.
:param context: Security context.
:param node_id: The node id.
:param name: Bios setting name to be deleted.
:raises: NodeNotFound if the node id is not found.
:raises: BIOSSettingNotFound if the bios setting name is not found.
"""
cls.dbapi.delete_bios_setting(node_id, name)
@base.IronicObjectRegistry.register
class BIOSSettingList(base.IronicObjectListBase, base.IronicObject):
# Version 1.0: Initial version
VERSION = '1.0'
dbapi = dbapi.get_instance()
fields = {
'objects': object_fields.ListOfObjectsField('BIOSSetting'),
}
# 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 create(cls, context, node_id, settings):
"""Create a list of BIOS Setting records in 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.: BIOSSetting(context)
:param node_id: The node id.
:param settings: A list of bios settings.
:raises: NodeNotFound if the node id is not found.
:raises: BIOSSettingAlreadyExists if any of the setting records
already exists.
:return: A list of BIOSSetting objects.
"""
version = BIOSSetting.get_target_version()
db_setting_list = cls.dbapi.create_bios_setting_list(
node_id, settings, version)
return object_base.obj_make_list(
context, cls(), BIOSSetting, db_setting_list)
# 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 save(cls, context, node_id, settings):
"""Save a list of BIOS Setting updates in 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.: BIOSSetting(context)
:param node_id: The node id.
:param settings: A list of bios settings.
:raises: NodeNotFound if the node id is not found.
:raises: BIOSSettingNotFound if any of the bios setting names
is not found.
:return: A list of BIOSSetting objects.
"""
version = BIOSSetting.get_target_version()
updated_setting_list = cls.dbapi.update_bios_setting_list(
node_id, settings, version)
return object_base.obj_make_list(
context, cls(), BIOSSetting, updated_setting_list)
# 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_node_id(cls, context, node_id):
"""Get BIOS Setting based on node_id.
:param context: Security context.
:param node_id: The node id.
:raises: NodeNotFound if the node id is not found.
:return: A list of BIOSSetting objects.
"""
node_bios_setting = cls.dbapi.get_bios_setting_list(node_id)
return object_base.obj_make_list(
context, cls(), BIOSSetting, node_bios_setting)

View File

@ -0,0 +1,149 @@
# 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 mock
from ironic.common import context
from ironic.db import api as dbapi
from ironic import objects
from ironic.tests.unit.db import base as db_base
from ironic.tests.unit.db import utils as db_utils
from ironic.tests.unit.objects import utils as obj_utils
class TestBIOSSettingObject(db_base.DbTestCase, obj_utils.SchemasTestMixIn):
def setUp(self):
super(TestBIOSSettingObject, self).setUp()
self.ctxt = context.get_admin_context()
self.bios_setting = db_utils.get_test_bios_setting()
self.node_id = self.bios_setting['node_id']
@mock.patch.object(dbapi.IMPL, 'get_bios_setting', autospec=True)
def test_get(self, mock_get_setting):
mock_get_setting.return_value = self.bios_setting
bios_obj = objects.BIOSSetting.get(self.context, self.node_id,
self.bios_setting['name'])
mock_get_setting.assert_called_once_with(self.node_id,
self.bios_setting['name'])
self.assertEqual(self.context, bios_obj._context)
self.assertEqual(self.bios_setting['node_id'], bios_obj.node_id)
self.assertEqual(self.bios_setting['name'], bios_obj.name)
self.assertEqual(self.bios_setting['value'], bios_obj.value)
@mock.patch.object(dbapi.IMPL, 'get_bios_setting_list', autospec=True)
def test_get_by_node_id(self, mock_get_setting_list):
bios_setting2 = db_utils.get_test_bios_setting(name='hyperthread',
value='enabled')
mock_get_setting_list.return_value = [self.bios_setting, bios_setting2]
bios_obj_list = objects.BIOSSettingList.get_by_node_id(
self.context, self.node_id)
mock_get_setting_list.assert_called_once_with(self.node_id)
self.assertEqual(self.context, bios_obj_list._context)
self.assertEqual(2, len(bios_obj_list))
self.assertEqual(self.bios_setting['node_id'],
bios_obj_list[0].node_id)
self.assertEqual(self.bios_setting['name'], bios_obj_list[0].name)
self.assertEqual(self.bios_setting['value'], bios_obj_list[0].value)
self.assertEqual(bios_setting2['node_id'], bios_obj_list[1].node_id)
self.assertEqual(bios_setting2['name'], bios_obj_list[1].name)
self.assertEqual(bios_setting2['value'], bios_obj_list[1].value)
@mock.patch.object(dbapi.IMPL, 'create_bios_setting_list', autospec=True)
def test_create(self, mock_create_list):
fake_call_args = {'node_id': self.bios_setting['node_id'],
'name': self.bios_setting['name'],
'value': self.bios_setting['value'],
'version': self.bios_setting['version']}
setting = [{'name': self.bios_setting['name'],
'value': self.bios_setting['value']}]
bios_obj = objects.BIOSSetting(context=self.context,
**fake_call_args)
mock_create_list.return_value = [self.bios_setting]
mock_create_list.call_args
bios_obj.create()
mock_create_list.assert_called_once_with(self.bios_setting['node_id'],
setting,
self.bios_setting['version'])
self.assertEqual(self.bios_setting['node_id'], bios_obj.node_id)
self.assertEqual(self.bios_setting['name'], bios_obj.name)
self.assertEqual(self.bios_setting['value'], bios_obj.value)
@mock.patch.object(dbapi.IMPL, 'update_bios_setting_list', autospec=True)
def test_save(self, mock_update_list):
fake_call_args = {'node_id': self.bios_setting['node_id'],
'name': self.bios_setting['name'],
'value': self.bios_setting['value'],
'version': self.bios_setting['version']}
setting = [{'name': self.bios_setting['name'],
'value': self.bios_setting['value']}]
bios_obj = objects.BIOSSetting(context=self.context,
**fake_call_args)
mock_update_list.return_value = [self.bios_setting]
mock_update_list.call_args
bios_obj.save()
mock_update_list.assert_called_once_with(self.bios_setting['node_id'],
setting,
self.bios_setting['version'])
self.assertEqual(self.bios_setting['node_id'], bios_obj.node_id)
self.assertEqual(self.bios_setting['name'], bios_obj.name)
self.assertEqual(self.bios_setting['value'], bios_obj.value)
@mock.patch.object(dbapi.IMPL, 'create_bios_setting_list', autospec=True)
def test_list_create(self, mock_create_list):
bios_setting2 = db_utils.get_test_bios_setting(name='hyperthread',
value='enabled')
settings = db_utils.get_test_bios_setting_setting_list()[:-1]
mock_create_list.return_value = [self.bios_setting, bios_setting2]
bios_obj_list = objects.BIOSSettingList.create(
self.context, self.node_id, settings)
mock_create_list.assert_called_once_with(self.node_id, settings, '1.0')
self.assertEqual(self.context, bios_obj_list._context)
self.assertEqual(2, len(bios_obj_list))
self.assertEqual(self.bios_setting['node_id'],
bios_obj_list[0].node_id)
self.assertEqual(self.bios_setting['name'], bios_obj_list[0].name)
self.assertEqual(self.bios_setting['value'], bios_obj_list[0].value)
self.assertEqual(bios_setting2['node_id'], bios_obj_list[1].node_id)
self.assertEqual(bios_setting2['name'], bios_obj_list[1].name)
self.assertEqual(bios_setting2['value'], bios_obj_list[1].value)
@mock.patch.object(dbapi.IMPL, 'update_bios_setting_list', autospec=True)
def test_list_save(self, mock_update_list):
bios_setting2 = db_utils.get_test_bios_setting(name='hyperthread',
value='enabled')
settings = db_utils.get_test_bios_setting_setting_list()[:-1]
mock_update_list.return_value = [self.bios_setting, bios_setting2]
bios_obj_list = objects.BIOSSettingList.save(
self.context, self.node_id, settings)
mock_update_list.assert_called_once_with(self.node_id, settings, '1.0')
self.assertEqual(self.context, bios_obj_list._context)
self.assertEqual(2, len(bios_obj_list))
self.assertEqual(self.bios_setting['node_id'],
bios_obj_list[0].node_id)
self.assertEqual(self.bios_setting['name'], bios_obj_list[0].name)
self.assertEqual(self.bios_setting['value'], bios_obj_list[0].value)
self.assertEqual(bios_setting2['node_id'], bios_obj_list[1].node_id)
self.assertEqual(bios_setting2['name'], bios_obj_list[1].name)
self.assertEqual(bios_setting2['value'], bios_obj_list[1].value)
@mock.patch.object(dbapi.IMPL, 'delete_bios_setting', autospec=True)
def test_delete(self, mock_delete):
objects.BIOSSetting.delete(self.context, self.node_id,
self.bios_setting['name'])
mock_delete.assert_called_once_with(self.node_id,
self.bios_setting['name'])

View File

@ -698,6 +698,8 @@ expected_object_fingerprints = {
'VolumeTargetCRUDPayload': '1.0-30dcc4735512c104a3a36a2ae1e2aeb2',
'Trait': '1.0-3f26cb70c8a10a3807d64c219453e347',
'TraitList': '1.0-33a2e1bb91ad4082f9f63429b77c1244',
'BIOSSetting': '1.0-fd4a791dc2139a7cc21cefbbaedfd9e7',
'BIOSSettingList': '1.0-33a2e1bb91ad4082f9f63429b77c1244',
}