Example #1
0
    def obj_to_primitive(self, target_version=None, version_manifest=None):
        """Simple base-case dehydration.

        This calls to_primitive() for each item in fields.
        """
        if target_version is None:
            target_version = self.VERSION
        if (utils.convert_version_to_tuple(target_version) >
                utils.convert_version_to_tuple(self.VERSION)):
            raise exception.InvalidTargetVersion(version=target_version)
        primitive = dict()
        for name, field in self.fields.items():
            if self.obj_attr_is_set(name):
                primitive[name] = field.to_primitive(self, name,
                                                     getattr(self, name))
        # NOTE(danms): If we know we're being asked for a different version,
        # then do the compat step. However, even if we think we're not,
        # we may have sub-objects that need it, so if we have a manifest we
        # have to traverse this object just in case. Previously, we
        # required a parent version bump for any child, so the target
        # check was enough.
        if target_version != self.VERSION or version_manifest:
            self.obj_make_compatible_from_manifest(primitive,
                                                   target_version,
                                                   version_manifest)
        obj = {self._obj_primitive_key('name'): self.obj_name(),
               self._obj_primitive_key('namespace'): (
                   self.OBJ_PROJECT_NAMESPACE),
               self._obj_primitive_key('version'): target_version,
               self._obj_primitive_key('data'): primitive}
        if self.obj_what_changed():
            obj[self._obj_primitive_key('changes')] = list(
                self.obj_what_changed())
        return obj
    def _obj_make_obj_compatible(self, primitive, target_version, field):
        """Backlevel a sub-object based on our versioning rules.

        This is responsible for backporting objects contained within
        this object's primitive according to a set of rules we
        maintain about version dependencies between objects. This
        requires that the obj_relationships table in this object is
        correct and up-to-date.

        :param:primitive: The primitive version of this object
        :param:target_version: The version string requested for this object
        :param:field: The name of the field in this object containing the
                      sub-object to be backported
        """

        def _do_backport(to_version):
            obj = getattr(self, field)
            if not obj:
                return
            if isinstance(obj, VersionedObject):
                obj.obj_make_compatible(
                    obj._obj_primitive_field(primitive[field], 'data'),
                    to_version)
                ver_key = obj._obj_primitive_key('version')
                primitive[field][ver_key] = to_version
            elif isinstance(obj, list):
                for i, element in enumerate(obj):
                    element.obj_make_compatible(
                        element._obj_primitive_field(primitive[field][i],
                                                     'data'),
                        to_version)
                    ver_key = element._obj_primitive_key('version')
                    primitive[field][i][ver_key] = to_version

        target_version = utils.convert_version_to_tuple(target_version)
        for index, versions in enumerate(self.obj_relationships[field]):
            my_version, child_version = versions
            my_version = utils.convert_version_to_tuple(my_version)
            if target_version < my_version:
                if index == 0:
                    # We're backporting to a version from before this
                    # subobject was added: delete it from the primitive.
                    del primitive[field]
                else:
                    # We're in the gap between index-1 and index, so
                    # backport to the older version
                    last_child_version = \
                        self.obj_relationships[field][index - 1][1]
                    _do_backport(last_child_version)
                return
            elif target_version == my_version:
                # This is the first mapping that satisfies the
                # target_version request: backport the object.
                _do_backport(child_version)
                return
Example #3
0
 def _test_relationships_in_order(self, obj_class):
     for field, versions in obj_class.obj_relationships.items():
         last_my_version = (0, 0)
         last_child_version = (0, 0)
         for my_version, child_version in versions:
             _my_version = utils.convert_version_to_tuple(my_version)
             _ch_version = utils.convert_version_to_tuple(child_version)
             assert (last_my_version < _my_version
                     and last_child_version <= _ch_version), \
                 ('Object %s relationship '
                  '%s->%s for field %s is out of order') % (
                      obj_class.obj_name(), my_version,
                      child_version, field)
             last_my_version = _my_version
             last_child_version = _ch_version
 def _test_relationships_in_order(self, obj_class):
     for field, versions in obj_class.obj_relationships.items():
         last_my_version = (0, 0)
         last_child_version = (0, 0)
         for my_version, child_version in versions:
             _my_version = utils.convert_version_to_tuple(my_version)
             _ch_version = utils.convert_version_to_tuple(child_version)
             assert (last_my_version < _my_version
                     and last_child_version <= _ch_version), \
                 ('Object %s relationship '
                  '%s->%s for field %s is out of order') % (
                      obj_class.obj_name(), my_version,
                      child_version, field)
             last_my_version = _my_version
             last_child_version = _ch_version
Example #5
0
 def _test_object_compatibility(self, obj_class):
     version = utils.convert_version_to_tuple(obj_class.VERSION)
     for n in range(version[1] + 1):
         test_version = '%d.%d' % (version[0], n)
         LOG.info('testing obj: %s version: %s' %
                  (obj_class.obj_name(), test_version))
         obj_class().obj_to_primitive(target_version=test_version)
 def _test_object_compatibility(self, obj_class):
     version = utils.convert_version_to_tuple(obj_class.VERSION)
     for n in range(version[1] + 1):
         test_version = '%d.%d' % (version[0], n)
         LOG.info('testing obj: %s version: %s' %
                  (obj_class.obj_name(), test_version))
         obj_class().obj_to_primitive(target_version=test_version)
Example #7
0
def _get_subobject_version(tgt_version, relationships, backport_func):
    """Get the version to which we need to convert a subobject.

    This uses the relationships between a parent and a subobject,
    along with the target parent version, to decide the version we need
    to convert a subobject to. If the subobject did not exist in the parent at
    the target version, TargetBeforeChildExistedException is raised. If there
    is a need to backport, backport_func is called and the subobject version
    to backport to is passed in.

    :param tgt_version: The version we are converting the parent to
    :param relationships: A list of (parent, subobject) version tuples
    :param backport_func: A backport function that takes in the subobject
                          version
    :returns: The version we need to convert the subobject to
    """
    tgt = utils.convert_version_to_tuple(tgt_version)
    for index, versions in enumerate(relationships):
        parent, child = versions
        parent = utils.convert_version_to_tuple(parent)
        if tgt < parent:
            if index == 0:
                # We're backporting to a version of the parent that did
                # not contain this subobject
                raise exception.TargetBeforeSubobjectExistedException(
                    target_version=tgt_version)
            else:
                # We're in a gap between index-1 and index, so set the desired
                # version to the previous index's version
                child = relationships[index - 1][1]
                backport_func(child)
            return
        elif tgt == parent:
            # We found the version we want, so backport to it
            backport_func(child)
            return
Example #8
0
 def test_convert_version_to_tuple(self):
     self.assertEqual(utils.convert_version_to_tuple('6.7.0'), (6, 7, 0))