Allow StringField to enforce max length

https://blueprints.launchpad.net/nova/+spec/string-field-max-length

This blueprint aims to add a max length constraint to the nova.objects.fields.StringField class.

Problem description

Currently, the nova object framework revolves around the use of field type classes that describe the schema of an object. Each object model is simply a collection of fields, each of which have a particular type, such as IntegerField or StringField.

In much the same way that a SQL database schema describes the constraints that a given column in a table must adhere to – e.g. the length of characters possible in a CHAR field, or a valid DATETIME string – the nova objects should be self-validating.

Proposed change

This specification proposes to change the coerce method of the String class to validate on the number of characters in the field’s string value.

The StringField concrete field class shall have a new max_length kwarg added to its constructor that will control the validation. The default value will be None, and no StringField objects defined in the schemas of any of the nova object models shall be changed in this spec.

Alternatives

None (keep things the way they are now)

Data model impact

None (the existing models themselves won’t be changed in this specification at all)

REST API impact

None

Security impact

None

Notifications impact

None

Other end user impact

None

Performance Impact

None

Other deployer impact

None

Developer impact

None

Implementation

Roughly, the code the String field type class would change from this:

class String(FieldType):
    @staticmethod
    def coerce(obj, attr, value):
        # FIXME(danms): We should really try to avoid the need to do this
        if isinstance(value, (six.string_types, int, long, float,
                              datetime.datetime)):
            return unicode(value)
        else:
            raise ValueError(_('A string is required here, not %s') %
                             value.__class__.__name__)

to this:

class String(FieldType):

    def __init__(self, max_length=None):
        """
        :param max_length: Optional constraint on the number of Unicode
                           characters the string value can be.
        """
        self._max_length = max_length

    @staticmethod
    def coerce(self, obj, attr, value):
        # FIXME(danms): We should really try to avoid the need to do this
        if isinstance(value, (six.string_types, int, long, float,
                              datetime.datetime)):
            result = unicode(value)
        else:
            raise ValueError(_('A string is required here, not %s') %
                             value.__class__.__name__)
        if self._max_length is not None:
            if len(value) > self._max_length):
                msg = _("String %(result)s is longer than maximum allowed "
                        "length of %(max_length)d.")
                msg = msg % dict(result=result,
                                 max_length=self._max_length)
                raise ValueError(msg)
        return result

The StringField class would then need to be modified to allow passing the max_length parameter along to its type class.

Work Items

N/A

Assignee(s)

Primary assignee:

jaypipes

Dependencies

None

Testing

Would need new unit tests. No need for any integration test changes.

Documentation Impact

None

References

The server-instance-tagging work will likely be the first work to use this functionality, as the tag string has a max length associated with it and we need to be very careful about changing existing model fields’ string length validation code, so a new field like the tag field is an ideal place to begin with this implementation.

http://git.openstack.org/cgit/openstack/nova-specs/tree/specs/juno/tag-instances.rst