Use oslo.versionedobjects remotable decorators

Use remotable decorators from oslo.versionedobjects.
remotable() treats context as option parameter, so change some tests
accordingly.

Change-Id: I84aef23cfa13a6162120e048477228015defc7e6
This commit is contained in:
Lin Tan 2015-08-26 14:36:03 +08:00
parent b94ff0bfe7
commit 318f038548
7 changed files with 48 additions and 107 deletions

View File

@ -347,10 +347,6 @@ class SSHCommandFailed(IronicException):
message = _("Failed to execute command via SSH: %(cmd)s.") message = _("Failed to execute command via SSH: %(cmd)s.")
class OrphanedObjectError(IronicException):
message = _('Cannot call %(method)s on orphaned %(objtype)s object')
class UnsupportedDriverExtension(Invalid): class UnsupportedDriverExtension(Invalid):
message = _('Driver %(driver)s does not support %(extension)s ' message = _('Driver %(driver)s does not support %(extension)s '
'(disabled or not implemented).') '(disabled or not implemented).')

View File

@ -14,7 +14,6 @@
"""Ironic common internal object model""" """Ironic common internal object model"""
from oslo_context import context
from oslo_log import log as logging from oslo_log import log as logging
from oslo_versionedobjects import base as object_base from oslo_versionedobjects import base as object_base
@ -30,59 +29,6 @@ class IronicObjectRegistry(object_base.VersionedObjectRegistry):
pass pass
# These are decorators that mark an object's method as remotable.
# If the metaclass is configured to forward object methods to an
# indirection service, these will result in making an RPC call
# instead of directly calling the implementation in the object. Instead,
# the object implementation on the remote end will perform the
# requested action and the result will be returned here.
def remotable_classmethod(fn):
"""Decorator for remotable classmethods."""
def wrapper(cls, context, *args, **kwargs):
if IronicObject.indirection_api:
result = IronicObject.indirection_api.object_class_action(
context, cls.obj_name(), fn.__name__, cls.VERSION,
args, kwargs)
else:
result = fn(cls, context, *args, **kwargs)
if isinstance(result, IronicObject):
result._context = context
return result
return classmethod(wrapper)
# See comment above for remotable_classmethod()
#
# Note that this will use either the provided context, or the one
# stashed in the object. If neither are present, the object is
# "orphaned" and remotable methods cannot be called.
def remotable(fn):
"""Decorator for remotable object methods."""
def wrapper(self, *args, **kwargs):
ctxt = self._context
try:
if isinstance(args[0], (context.RequestContext)):
ctxt = args[0]
args = args[1:]
except IndexError:
pass
if ctxt is None:
raise exception.OrphanedObjectError(method=fn.__name__,
objtype=self.obj_name())
if IronicObject.indirection_api:
updates, result = IronicObject.indirection_api.object_action(
ctxt, self, fn.__name__, args, kwargs)
for key, value in updates.items():
if key in self.fields:
field = self.fields[key]
self[key] = field.from_primitive(self, key, value)
self._changed_fields = set(updates.get('obj_what_changed', []))
return result
else:
return fn(self, ctxt, *args, **kwargs)
return wrapper
# Object versioning rules # Object versioning rules
# #
# Each service has its set of objects, each with a version attached. When # Each service has its set of objects, each with a version attached. When

View File

@ -55,7 +55,7 @@ class Chassis(base.IronicObject, object_base.VersionedObjectDictCompat):
chassis.obj_reset_changes() chassis.obj_reset_changes()
return chassis return chassis
@base.remotable_classmethod @object_base.remotable_classmethod
def get(cls, context, chassis_id): def get(cls, context, chassis_id):
"""Find a chassis based on its id or uuid and return a Chassis object. """Find a chassis based on its id or uuid and return a Chassis object.
@ -69,7 +69,7 @@ class Chassis(base.IronicObject, object_base.VersionedObjectDictCompat):
else: else:
raise exception.InvalidIdentity(identity=chassis_id) raise exception.InvalidIdentity(identity=chassis_id)
@base.remotable_classmethod @object_base.remotable_classmethod
def get_by_id(cls, context, chassis_id): def get_by_id(cls, context, chassis_id):
"""Find a chassis based on its integer id and return a Chassis object. """Find a chassis based on its integer id and return a Chassis object.
@ -80,7 +80,7 @@ class Chassis(base.IronicObject, object_base.VersionedObjectDictCompat):
chassis = Chassis._from_db_object(cls(context), db_chassis) chassis = Chassis._from_db_object(cls(context), db_chassis)
return chassis return chassis
@base.remotable_classmethod @object_base.remotable_classmethod
def get_by_uuid(cls, context, uuid): def get_by_uuid(cls, context, uuid):
"""Find a chassis based on uuid and return a :class:`Chassis` object. """Find a chassis based on uuid and return a :class:`Chassis` object.
@ -92,7 +92,7 @@ class Chassis(base.IronicObject, object_base.VersionedObjectDictCompat):
chassis = Chassis._from_db_object(cls(context), db_chassis) chassis = Chassis._from_db_object(cls(context), db_chassis)
return chassis return chassis
@base.remotable_classmethod @object_base.remotable_classmethod
def list(cls, context, limit=None, marker=None, def list(cls, context, limit=None, marker=None,
sort_key=None, sort_dir=None): sort_key=None, sort_dir=None):
"""Return a list of Chassis objects. """Return a list of Chassis objects.
@ -112,7 +112,7 @@ class Chassis(base.IronicObject, object_base.VersionedObjectDictCompat):
return [Chassis._from_db_object(cls(context), obj) return [Chassis._from_db_object(cls(context), obj)
for obj in db_chassis] for obj in db_chassis]
@base.remotable @object_base.remotable
def create(self, context=None): def create(self, context=None):
"""Create a Chassis record in the DB. """Create a Chassis record in the DB.
@ -133,7 +133,7 @@ class Chassis(base.IronicObject, object_base.VersionedObjectDictCompat):
db_chassis = self.dbapi.create_chassis(values) db_chassis = self.dbapi.create_chassis(values)
self._from_db_object(self, db_chassis) self._from_db_object(self, db_chassis)
@base.remotable @object_base.remotable
def destroy(self, context=None): def destroy(self, context=None):
"""Delete the Chassis from the DB. """Delete the Chassis from the DB.
@ -147,7 +147,7 @@ class Chassis(base.IronicObject, object_base.VersionedObjectDictCompat):
self.dbapi.destroy_chassis(self.uuid) self.dbapi.destroy_chassis(self.uuid)
self.obj_reset_changes() self.obj_reset_changes()
@base.remotable @object_base.remotable
def save(self, context=None): def save(self, context=None):
"""Save updates to this Chassis. """Save updates to this Chassis.
@ -165,7 +165,7 @@ class Chassis(base.IronicObject, object_base.VersionedObjectDictCompat):
updated_chassis = self.dbapi.update_chassis(self.uuid, updates) updated_chassis = self.dbapi.update_chassis(self.uuid, updates)
self._from_db_object(self, updated_chassis) self._from_db_object(self, updated_chassis)
@base.remotable @object_base.remotable
def refresh(self, context=None): def refresh(self, context=None):
"""Loads and applies updates for this Chassis. """Loads and applies updates for this Chassis.

View File

@ -42,7 +42,7 @@ class Conductor(base.IronicObject, object_base.VersionedObjectDictCompat):
conductor.obj_reset_changes() conductor.obj_reset_changes()
return conductor return conductor
@base.remotable_classmethod @object_base.remotable_classmethod
def get_by_hostname(cls, context, hostname): def get_by_hostname(cls, context, hostname):
"""Get a Conductor record by its hostname. """Get a Conductor record by its hostname.
@ -58,7 +58,7 @@ class Conductor(base.IronicObject, object_base.VersionedObjectDictCompat):
raise NotImplementedError( raise NotImplementedError(
_('Cannot update a conductor record directly.')) _('Cannot update a conductor record directly.'))
@base.remotable @object_base.remotable
def refresh(self, context=None): def refresh(self, context=None):
"""Loads and applies updates for this Conductor. """Loads and applies updates for this Conductor.
@ -77,7 +77,7 @@ class Conductor(base.IronicObject, object_base.VersionedObjectDictCompat):
hostname=self.hostname) hostname=self.hostname)
self.obj_refresh(current) self.obj_refresh(current)
@base.remotable @object_base.remotable
def touch(self, context): def touch(self, context):
"""Touch this conductor's DB record, marking it as up-to-date.""" """Touch this conductor's DB record, marking it as up-to-date."""
self.dbapi.touch_conductor(self.hostname) self.dbapi.touch_conductor(self.hostname)

View File

@ -106,7 +106,7 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):
node.obj_reset_changes() node.obj_reset_changes()
return node return node
@base.remotable_classmethod @object_base.remotable_classmethod
def get(cls, context, node_id): def get(cls, context, node_id):
"""Find a node based on its id or uuid and return a Node object. """Find a node based on its id or uuid and return a Node object.
@ -120,7 +120,7 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):
else: else:
raise exception.InvalidIdentity(identity=node_id) raise exception.InvalidIdentity(identity=node_id)
@base.remotable_classmethod @object_base.remotable_classmethod
def get_by_id(cls, context, node_id): def get_by_id(cls, context, node_id):
"""Find a node based on its integer id and return a Node object. """Find a node based on its integer id and return a Node object.
@ -131,7 +131,7 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):
node = Node._from_db_object(cls(context), db_node) node = Node._from_db_object(cls(context), db_node)
return node return node
@base.remotable_classmethod @object_base.remotable_classmethod
def get_by_uuid(cls, context, uuid): def get_by_uuid(cls, context, uuid):
"""Find a node based on uuid and return a Node object. """Find a node based on uuid and return a Node object.
@ -142,7 +142,7 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):
node = Node._from_db_object(cls(context), db_node) node = Node._from_db_object(cls(context), db_node)
return node return node
@base.remotable_classmethod @object_base.remotable_classmethod
def get_by_name(cls, context, name): def get_by_name(cls, context, name):
"""Find a node based on name and return a Node object. """Find a node based on name and return a Node object.
@ -153,7 +153,7 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):
node = Node._from_db_object(cls(context), db_node) node = Node._from_db_object(cls(context), db_node)
return node return node
@base.remotable_classmethod @object_base.remotable_classmethod
def get_by_instance_uuid(cls, context, instance_uuid): def get_by_instance_uuid(cls, context, instance_uuid):
"""Find a node based on the instance uuid and return a Node object. """Find a node based on the instance uuid and return a Node object.
@ -164,7 +164,7 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):
node = Node._from_db_object(cls(context), db_node) node = Node._from_db_object(cls(context), db_node)
return node return node
@base.remotable_classmethod @object_base.remotable_classmethod
def list(cls, context, limit=None, marker=None, sort_key=None, def list(cls, context, limit=None, marker=None, sort_key=None,
sort_dir=None, filters=None): sort_dir=None, filters=None):
"""Return a list of Node objects. """Return a list of Node objects.
@ -183,7 +183,7 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):
sort_dir=sort_dir) sort_dir=sort_dir)
return [Node._from_db_object(cls(context), obj) for obj in db_nodes] return [Node._from_db_object(cls(context), obj) for obj in db_nodes]
@base.remotable_classmethod @object_base.remotable_classmethod
def reserve(cls, context, tag, node_id): def reserve(cls, context, tag, node_id):
"""Get and reserve a node. """Get and reserve a node.
@ -201,7 +201,7 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):
node = Node._from_db_object(cls(context), db_node) node = Node._from_db_object(cls(context), db_node)
return node return node
@base.remotable_classmethod @object_base.remotable_classmethod
def release(cls, context, tag, node_id): def release(cls, context, tag, node_id):
"""Release the reservation on a node. """Release the reservation on a node.
@ -213,7 +213,7 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):
""" """
cls.dbapi.release_node(tag, node_id) cls.dbapi.release_node(tag, node_id)
@base.remotable @object_base.remotable
def create(self, context=None): def create(self, context=None):
"""Create a Node record in the DB. """Create a Node record in the DB.
@ -234,7 +234,7 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):
db_node = self.dbapi.create_node(values) db_node = self.dbapi.create_node(values)
self._from_db_object(self, db_node) self._from_db_object(self, db_node)
@base.remotable @object_base.remotable
def destroy(self, context=None): def destroy(self, context=None):
"""Delete the Node from the DB. """Delete the Node from the DB.
@ -248,7 +248,7 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):
self.dbapi.destroy_node(self.uuid) self.dbapi.destroy_node(self.uuid)
self.obj_reset_changes() self.obj_reset_changes()
@base.remotable @object_base.remotable
def save(self, context=None): def save(self, context=None):
"""Save updates to this Node. """Save updates to this Node.
@ -272,7 +272,7 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):
self.dbapi.update_node(self.uuid, updates) self.dbapi.update_node(self.uuid, updates)
self.obj_reset_changes() self.obj_reset_changes()
@base.remotable @object_base.remotable
def refresh(self, context=None): def refresh(self, context=None):
"""Refresh the object by re-fetching from the DB. """Refresh the object by re-fetching from the DB.
@ -286,7 +286,7 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):
current = self.__class__.get_by_uuid(self._context, self.uuid) current = self.__class__.get_by_uuid(self._context, self.uuid)
self.obj_refresh(current) self.obj_refresh(current)
@base.remotable @object_base.remotable
def touch_provisioning(self, context=None): def touch_provisioning(self, context=None):
"""Touch the database record to mark the provisioning as alive.""" """Touch the database record to mark the provisioning as alive."""
self.dbapi.touch_node_provisioning(self.id) self.dbapi.touch_node_provisioning(self.id)

View File

@ -58,7 +58,7 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
"""Converts a list of database entities to a list of formal objects.""" """Converts a list of database entities to a list of formal objects."""
return [Port._from_db_object(cls(context), obj) for obj in db_objects] return [Port._from_db_object(cls(context), obj) for obj in db_objects]
@base.remotable_classmethod @object_base.remotable_classmethod
def get(cls, context, port_id): def get(cls, context, port_id):
"""Find a port based on its id or uuid and return a Port object. """Find a port based on its id or uuid and return a Port object.
@ -76,7 +76,7 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
else: else:
raise exception.InvalidIdentity(identity=port_id) raise exception.InvalidIdentity(identity=port_id)
@base.remotable_classmethod @object_base.remotable_classmethod
def get_by_id(cls, context, port_id): def get_by_id(cls, context, port_id):
"""Find a port based on its integer id and return a Port object. """Find a port based on its integer id and return a Port object.
@ -89,7 +89,7 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
port = Port._from_db_object(cls(context), db_port) port = Port._from_db_object(cls(context), db_port)
return port return port
@base.remotable_classmethod @object_base.remotable_classmethod
def get_by_uuid(cls, context, uuid): def get_by_uuid(cls, context, uuid):
"""Find a port based on uuid and return a :class:`Port` object. """Find a port based on uuid and return a :class:`Port` object.
@ -103,7 +103,7 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
port = Port._from_db_object(cls(context), db_port) port = Port._from_db_object(cls(context), db_port)
return port return port
@base.remotable_classmethod @object_base.remotable_classmethod
def get_by_address(cls, context, address): def get_by_address(cls, context, address):
"""Find a port based on address and return a :class:`Port` object. """Find a port based on address and return a :class:`Port` object.
@ -117,7 +117,7 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
port = Port._from_db_object(cls(context), db_port) port = Port._from_db_object(cls(context), db_port)
return port return port
@base.remotable_classmethod @object_base.remotable_classmethod
def list(cls, context, limit=None, marker=None, def list(cls, context, limit=None, marker=None,
sort_key=None, sort_dir=None): sort_key=None, sort_dir=None):
"""Return a list of Port objects. """Return a list of Port objects.
@ -137,7 +137,7 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
sort_dir=sort_dir) sort_dir=sort_dir)
return Port._from_db_object_list(db_ports, cls, context) return Port._from_db_object_list(db_ports, cls, context)
@base.remotable_classmethod @object_base.remotable_classmethod
def list_by_node_id(cls, context, node_id, limit=None, marker=None, def list_by_node_id(cls, context, node_id, limit=None, marker=None,
sort_key=None, sort_dir=None): sort_key=None, sort_dir=None):
"""Return a list of Port objects associated with a given node ID. """Return a list of Port objects associated with a given node ID.
@ -157,7 +157,7 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
sort_dir=sort_dir) sort_dir=sort_dir)
return Port._from_db_object_list(db_ports, cls, context) return Port._from_db_object_list(db_ports, cls, context)
@base.remotable @object_base.remotable
def create(self, context=None): def create(self, context=None):
"""Create a Port record in the DB. """Create a Port record in the DB.
@ -175,7 +175,7 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
db_port = self.dbapi.create_port(values) db_port = self.dbapi.create_port(values)
self._from_db_object(self, db_port) self._from_db_object(self, db_port)
@base.remotable @object_base.remotable
def destroy(self, context=None): def destroy(self, context=None):
"""Delete the Port from the DB. """Delete the Port from the DB.
@ -191,7 +191,7 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
self.dbapi.destroy_port(self.uuid) self.dbapi.destroy_port(self.uuid)
self.obj_reset_changes() self.obj_reset_changes()
@base.remotable @object_base.remotable
def save(self, context=None): def save(self, context=None):
"""Save updates to this Port. """Save updates to this Port.
@ -212,7 +212,7 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat):
updated_port = self.dbapi.update_port(self.uuid, updates) updated_port = self.dbapi.update_port(self.uuid, updates)
self._from_db_object(self, updated_port) self._from_db_object(self, updated_port)
@base.remotable @object_base.remotable
def refresh(self, context=None): def refresh(self, context=None):
"""Loads updates for this Port. """Loads updates for this Port.

View File

@ -23,7 +23,6 @@ from oslo_versionedobjects import base as object_base
from oslo_versionedobjects import exception as object_exception from oslo_versionedobjects import exception as object_exception
import six import six
from ironic.common import exception
from ironic.objects import base from ironic.objects import base
from ironic.objects import fields from ironic.objects import fields
from ironic.objects import utils from ironic.objects import utils
@ -44,7 +43,7 @@ class MyObj(base.IronicObject, object_base.VersionedObjectDictCompat):
def obj_load_attr(self, attrname): def obj_load_attr(self, attrname):
setattr(self, attrname, 'loaded!') setattr(self, attrname, 'loaded!')
@base.remotable_classmethod @object_base.remotable_classmethod
def query(cls, context): def query(cls, context):
obj = cls(context) obj = cls(context)
obj.foo = 1 obj.foo = 1
@ -52,29 +51,29 @@ class MyObj(base.IronicObject, object_base.VersionedObjectDictCompat):
obj.obj_reset_changes() obj.obj_reset_changes()
return obj return obj
@base.remotable @object_base.remotable
def marco(self, context): def marco(self, context=None):
return 'polo' return 'polo'
@base.remotable @object_base.remotable
def update_test(self, context): def update_test(self, context=None):
if context.tenant == 'alternate': if context and context.tenant == 'alternate':
self.bar = 'alternate-context' self.bar = 'alternate-context'
else: else:
self.bar = 'updated' self.bar = 'updated'
@base.remotable @object_base.remotable
def save(self, context): def save(self, context=None):
self.obj_reset_changes() self.obj_reset_changes()
@base.remotable @object_base.remotable
def refresh(self, context): def refresh(self, context=None):
self.foo = 321 self.foo = 321
self.bar = 'refreshed' self.bar = 'refreshed'
self.obj_reset_changes() self.obj_reset_changes()
@base.remotable @object_base.remotable
def modify_save_modify(self, context): def modify_save_modify(self, context=None):
self.bar = 'meow' self.bar = 'meow'
self.save() self.save()
self.foo = 42 self.foo = 42
@ -85,7 +84,7 @@ class MyObj2(object):
def obj_name(cls): def obj_name(cls):
return 'MyObj' return 'MyObj'
@base.remotable_classmethod @object_base.remotable_classmethod
def get(cls, *args, **kwargs): def get(cls, *args, **kwargs):
pass pass
@ -257,7 +256,7 @@ class _TestObject(object):
def test_orphaned_object(self): def test_orphaned_object(self):
obj = MyObj.query(self.context) obj = MyObj.query(self.context)
obj._context = None obj._context = None
self.assertRaises(exception.OrphanedObjectError, self.assertRaises(object_exception.OrphanedObjectError,
obj.update_test) obj.update_test)
self.assertRemotes() self.assertRemotes()