From db9ddd39d3f3d854d38e4b05655ebddd98f1a727 Mon Sep 17 00:00:00 2001 From: Grzegorz Grasza Date: Wed, 16 Sep 2015 15:12:42 +0200 Subject: Implement indirection_api During a rolling upgrade, ironic conductor and api services are running with different versions. When an object is received in an incompatible version, IncompatibleObjectVersion is raised. Implementation of the indirection API allows the object to be backported to a supported version by the conductor (conductor has to be the first service to be upgraded). This change enables backporting of objects from Mitaka. This lays the foundation to be able to do rolling upgrades from Liberty (or from this patch onwards) to Mitaka. There may still be other issues that will need fixing in Mitaka before we will be able to do a full rolling upgrade. Enabling the indirection_api causes all object methods decorated with the remotable or remotable_classmethod to do RPC from ironic-api to ironic-conductor service. To keep the current behavior, I'm removing all remotable decorators on object methods and thus not enabling object RPC calls in this patch. These calls caused random timeouts on the CI gates (probably due to a race in which Nova calls the ironic-api service before ironic-conductor is up). RPC calls made via the indirection_api should be enabled one-by-one, when the implications are fully understood. Change-Id: Ia381348da93f95d764c83f3ec2a2ed5a1db5ad6d Closes-Bug: 1493816 Depends-On: I81400305f166d62aa4612aab54602abb8178b64c --- ironic/objects/base.py | 30 +++++++++++++++++++ ironic/objects/chassis.py | 44 ++++++++++++++++++++++----- ironic/objects/conductor.py | 16 ++++++++-- ironic/objects/node.py | 73 +++++++++++++++++++++++++++++++++++++-------- ironic/objects/port.py | 56 +++++++++++++++++++++++++++------- 5 files changed, 185 insertions(+), 34 deletions(-) (limited to 'ironic/objects') diff --git a/ironic/objects/base.py b/ironic/objects/base.py index 14ef1aadf..56bb71ed7 100644 --- a/ironic/objects/base.py +++ b/ironic/objects/base.py @@ -65,6 +65,36 @@ class IronicObject(object_base.VersionedObject): self[field] = loaded_object[field] +class IronicObjectIndirectionAPI(object_base.VersionedObjectIndirectionAPI): + def __init__(self): + super(IronicObjectIndirectionAPI, self).__init__() + # FIXME(xek): importing here due to a cyclical import error + from ironic.conductor import rpcapi as conductor_api + self._conductor = conductor_api.ConductorAPI() + + def object_action(self, context, objinst, objmethod, args, kwargs): + return self._conductor.object_action(context, objinst, objmethod, + args, kwargs) + + def object_class_action(self, context, objname, objmethod, objver, + args, kwargs): + # NOTE(xek): This method is implemented for compatibility with + # oslo.versionedobjects 0.10.0 and older. It will be replaced by + # object_class_action_versions. + versions = object_base.obj_tree_get_versions(objname) + return self.object_class_action_versions( + context, objname, objmethod, versions, args, kwargs) + + def object_class_action_versions(self, context, objname, objmethod, + object_versions, args, kwargs): + return self._conductor.object_class_action_versions( + context, objname, objmethod, object_versions, args, kwargs) + + def object_backport_versions(self, context, objinst, object_versions): + return self._conductor.object_backport_versions(context, objinst, + object_versions) + + class IronicObjectSerializer(object_base.VersionedObjectSerializer): # Base class to use for object hydration OBJ_BASE_CLASS = IronicObject diff --git a/ironic/objects/chassis.py b/ironic/objects/chassis.py index 226a5db4a..8983ca0a7 100644 --- a/ironic/objects/chassis.py +++ b/ironic/objects/chassis.py @@ -55,7 +55,11 @@ class Chassis(base.IronicObject, object_base.VersionedObjectDictCompat): chassis.obj_reset_changes() return chassis - @object_base.remotable_classmethod + # 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, chassis_id): """Find a chassis based on its id or uuid and return a Chassis object. @@ -69,7 +73,11 @@ class Chassis(base.IronicObject, object_base.VersionedObjectDictCompat): else: raise exception.InvalidIdentity(identity=chassis_id) - @object_base.remotable_classmethod + # 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, chassis_id): """Find a chassis based on its integer id and return a Chassis object. @@ -80,7 +88,11 @@ class Chassis(base.IronicObject, object_base.VersionedObjectDictCompat): chassis = Chassis._from_db_object(cls(context), db_chassis) return chassis - @object_base.remotable_classmethod + # 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 chassis based on uuid and return a :class:`Chassis` object. @@ -92,7 +104,11 @@ class Chassis(base.IronicObject, object_base.VersionedObjectDictCompat): chassis = Chassis._from_db_object(cls(context), db_chassis) return chassis - @object_base.remotable_classmethod + # 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 Chassis objects. @@ -112,7 +128,10 @@ class Chassis(base.IronicObject, object_base.VersionedObjectDictCompat): return [Chassis._from_db_object(cls(context), obj) for obj in db_chassis] - @object_base.remotable + # 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 Chassis record in the DB. @@ -133,7 +152,10 @@ class Chassis(base.IronicObject, object_base.VersionedObjectDictCompat): db_chassis = self.dbapi.create_chassis(values) self._from_db_object(self, db_chassis) - @object_base.remotable + # 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 Chassis from the DB. @@ -147,7 +169,10 @@ class Chassis(base.IronicObject, object_base.VersionedObjectDictCompat): self.dbapi.destroy_chassis(self.uuid) self.obj_reset_changes() - @object_base.remotable + # 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 Chassis. @@ -165,7 +190,10 @@ class Chassis(base.IronicObject, object_base.VersionedObjectDictCompat): updated_chassis = self.dbapi.update_chassis(self.uuid, updates) self._from_db_object(self, updated_chassis) - @object_base.remotable + # 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 and applies updates for this Chassis. diff --git a/ironic/objects/conductor.py b/ironic/objects/conductor.py index eaf98447c..e0028e93a 100644 --- a/ironic/objects/conductor.py +++ b/ironic/objects/conductor.py @@ -42,7 +42,11 @@ class Conductor(base.IronicObject, object_base.VersionedObjectDictCompat): conductor.obj_reset_changes() return conductor - @object_base.remotable_classmethod + # 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_hostname(cls, context, hostname): """Get a Conductor record by its hostname. @@ -58,7 +62,10 @@ class Conductor(base.IronicObject, object_base.VersionedObjectDictCompat): raise NotImplementedError( _('Cannot update a conductor record directly.')) - @object_base.remotable + # 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 and applies updates for this Conductor. @@ -77,7 +84,10 @@ class Conductor(base.IronicObject, object_base.VersionedObjectDictCompat): hostname=self.hostname) self.obj_refresh(current) - @object_base.remotable + # 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 touch(self, context): """Touch this conductor's DB record, marking it as up-to-date.""" self.dbapi.touch_conductor(self.hostname) diff --git a/ironic/objects/node.py b/ironic/objects/node.py index 483b65426..b358c3adf 100644 --- a/ironic/objects/node.py +++ b/ironic/objects/node.py @@ -106,7 +106,11 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat): node.obj_reset_changes() return node - @object_base.remotable_classmethod + # 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): """Find a node based on its id or uuid and return a Node object. @@ -120,7 +124,11 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat): else: raise exception.InvalidIdentity(identity=node_id) - @object_base.remotable_classmethod + # 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, node_id): """Find a node based on its integer id and return a Node object. @@ -131,7 +139,11 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat): node = Node._from_db_object(cls(context), db_node) return node - @object_base.remotable_classmethod + # 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 node based on uuid and return a Node object. @@ -142,7 +154,11 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat): node = Node._from_db_object(cls(context), db_node) return node - @object_base.remotable_classmethod + # 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 node based on name and return a Node object. @@ -153,7 +169,11 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat): node = Node._from_db_object(cls(context), db_node) return node - @object_base.remotable_classmethod + # 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_instance_uuid(cls, context, instance_uuid): """Find a node based on the instance uuid and return a Node object. @@ -164,7 +184,11 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat): node = Node._from_db_object(cls(context), db_node) return node - @object_base.remotable_classmethod + # 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, filters=None): """Return a list of Node objects. @@ -183,7 +207,11 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat): sort_dir=sort_dir) return [Node._from_db_object(cls(context), obj) for obj in db_nodes] - @object_base.remotable_classmethod + # 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 reserve(cls, context, tag, node_id): """Get and reserve a node. @@ -201,7 +229,11 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat): node = Node._from_db_object(cls(context), db_node) return node - @object_base.remotable_classmethod + # 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 release(cls, context, tag, node_id): """Release the reservation on a node. @@ -213,7 +245,10 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat): """ cls.dbapi.release_node(tag, node_id) - @object_base.remotable + # 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 Node record in the DB. @@ -234,7 +269,10 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat): db_node = self.dbapi.create_node(values) self._from_db_object(self, db_node) - @object_base.remotable + # 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 Node from the DB. @@ -248,7 +286,10 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat): self.dbapi.destroy_node(self.uuid) self.obj_reset_changes() - @object_base.remotable + # 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 Node. @@ -272,7 +313,10 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat): self.dbapi.update_node(self.uuid, updates) self.obj_reset_changes() - @object_base.remotable + # 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): """Refresh the object by re-fetching from the DB. @@ -286,7 +330,10 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat): current = self.__class__.get_by_uuid(self._context, self.uuid) self.obj_refresh(current) - @object_base.remotable + # 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 touch_provisioning(self, context=None): """Touch the database record to mark the provisioning as alive.""" self.dbapi.touch_node_provisioning(self.id) diff --git a/ironic/objects/port.py b/ironic/objects/port.py index c145d66ed..5e9cd8cd5 100644 --- a/ironic/objects/port.py +++ b/ironic/objects/port.py @@ -58,7 +58,11 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat): """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] - @object_base.remotable_classmethod + # 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, port_id): """Find a port based on its id or uuid and return a Port object. @@ -76,7 +80,11 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat): else: raise exception.InvalidIdentity(identity=port_id) - @object_base.remotable_classmethod + # 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, port_id): """Find a port based on its integer id and return a Port object. @@ -89,7 +97,11 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat): port = Port._from_db_object(cls(context), db_port) return port - @object_base.remotable_classmethod + # 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 port based on uuid and return a :class:`Port` object. @@ -103,7 +115,11 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat): port = Port._from_db_object(cls(context), db_port) return port - @object_base.remotable_classmethod + # 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 port based on address and return a :class:`Port` object. @@ -117,7 +133,11 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat): port = Port._from_db_object(cls(context), db_port) return port - @object_base.remotable_classmethod + # 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 Port objects. @@ -137,7 +157,11 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat): sort_dir=sort_dir) return Port._from_db_object_list(db_ports, cls, context) - @object_base.remotable_classmethod + # 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 Port objects associated with a given node ID. @@ -157,7 +181,10 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat): sort_dir=sort_dir) return Port._from_db_object_list(db_ports, cls, context) - @object_base.remotable + # 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 Port record in the DB. @@ -175,7 +202,10 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat): db_port = self.dbapi.create_port(values) self._from_db_object(self, db_port) - @object_base.remotable + # 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 Port from the DB. @@ -191,7 +221,10 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat): self.dbapi.destroy_port(self.uuid) self.obj_reset_changes() - @object_base.remotable + # 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 Port. @@ -212,7 +245,10 @@ class Port(base.IronicObject, object_base.VersionedObjectDictCompat): updated_port = self.dbapi.update_port(self.uuid, updates) self._from_db_object(self, updated_port) - @object_base.remotable + # 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 Port. -- cgit v1.2.1