Skip to content

Commit

Permalink
Refactored DictField + Added value size limit to metadata field
Browse files Browse the repository at this point in the history
  • Loading branch information
dn0 committed Dec 13, 2017
1 parent ea1594f commit 9cfc03c
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 12 deletions.
2 changes: 1 addition & 1 deletion api/dc/base/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ class DcSettingsSerializer(s.InstanceSerializer):
VMS_VM_SSH_KEYS_DEFAULT = s.ArrayField(label='VMS_VM_SSH_KEYS_DEFAULT', max_items=32, required=False,
help_text=_('List of public SSH keys added to every virtual machine '
'in this virtual datacenter.'))
VMS_VM_MDATA_DEFAULT = s.MetadataField(label='VMS_VM_MDATA_DEFAULT', max_items=32, required=False,
VMS_VM_MDATA_DEFAULT = s.MetadataField(label='VMS_VM_MDATA_DEFAULT', required=False,
validators=(validate_mdata(Vm.RESERVED_MDATA_KEYS),),
help_text=_('Default VM metadata (key=value string pairs).'))
VMS_DISK_MODEL_DEFAULT = s.ChoiceField(label='VMS_DISK_MODEL_DEFAULT', choices=Vm.DISK_MODEL,
Expand Down
32 changes: 24 additions & 8 deletions api/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
from django.utils.translation import ugettext_lazy as _
from django.utils.dateparse import parse_date, parse_datetime, parse_time
from taggit.utils import parse_tags, split_strip
from frozendict import frozendict

from api import settings as api_settings
from api.settings import ISO_8601
Expand Down Expand Up @@ -1375,12 +1376,18 @@ class BaseDictField(WritableField):
"""
Dictionary - object.
"""
_key_field = NotImplemented
_val_field = NotImplemented
_key_field_class = NotImplemented
_key_field_params = frozendict()
_val_field_class = NotImplemented
_val_field_params = frozendict()
_default_max_size = None

def __init__(self, *args, **kwargs):
self.max_items = kwargs.pop('max_items', None)
self.max_size = kwargs.pop('max_size', self._default_max_size) # bytes
super(BaseDictField, self).__init__(*args, **kwargs)
self._key_field = self._key_field_class(**self._key_field_params)
self._val_field = self._val_field_class(**self._val_field_params)

def to_native(self, value):
ret = {}
Expand Down Expand Up @@ -1420,6 +1427,12 @@ def validate(self, value):
raise ValidationError(_('Ensure this value has at most %(max)d items (it has %(count)d).') %
{'max': self.max_items, 'count': count})

if self.max_size:
size = sum(len(val) for key, val in items)
if size > self.max_size:
raise ValidationError(_('Ensure this value has maximum size of %(max)d bytes '
'(it has %(size)d bytes).') % {'max': self.max_size, 'size': size})

for k, v in items:
self._key_field.validate(k)
self._val_field.validate(v)
Expand All @@ -1438,18 +1451,21 @@ class RoutesField(BaseDictField):
"10.3.0.1": "nics[1]"
}
"""
_key_field = CIDRField()
_val_field = IPNICField()
_key_field_class = CIDRField
_val_field_class = IPNICField


class MetadataField(BaseDictField):
_key_field = RegexField(r'^[A-Za-z0-9\.\-_:]+$', max_length=128)
_val_field = CharField(max_length=65536)
_key_field_class = RegexField
_key_field_params = frozendict(regex=r'^[A-Za-z0-9\.\-_:]+$', max_length=128)
_val_field_class = CharField
_default_max_size = 1024 * 1024 * 8 # 8 MB (mentioned in user guide)


class URLDictField(BaseDictField):
_key_field = RegexField(r'^[a-z0-9][a-z0-9\.\-_]*$', max_length=32)
_val_field = URLField()
_key_field_class = RegexField
_key_field_params = frozendict(regex=r'^[a-z0-9][a-z0-9\.\-_]*$', max_length=32)
_val_field_class = URLField


class SafeCharField(RegexField):
Expand Down
2 changes: 1 addition & 1 deletion api/vm/define/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ class VmDefineSerializer(VmBaseSerializer):
maintain_resolvers = s.BooleanField(default=True) # OS only
routes = s.RoutesField(default={}) # OS only
vga = s.ChoiceField(choices=Vm.VGA_MODEL, default=settings.VMS_VGA_MODEL_DEFAULT) # KVM only
mdata = s.MetadataField(max_items=32, default=settings.VMS_VM_MDATA_DEFAULT,
mdata = s.MetadataField(default=settings.VMS_VM_MDATA_DEFAULT,
validators=(validate_mdata(Vm.RESERVED_MDATA_KEYS),))
locked = s.BooleanField(read_only=True, required=False)
created = s.DateTimeField(read_only=True, required=False)
Expand Down
7 changes: 5 additions & 2 deletions api/vm/migrate/serializers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from django.utils.translation import ugettext_lazy as _
from django.core.exceptions import ObjectDoesNotExist
from frozendict import frozendict

from api import serializers as s
from api.serializers import APIValidationError
Expand All @@ -14,8 +15,10 @@


class DiskPoolDictField(s.BaseDictField):
_key_field = s.IntegerField(min_value=DISK_ID_MIN + 1, max_value=DISK_ID_MAX + 1)
_val_field = s.CharField(max_length=64)
_key_field_class = s.IntegerField
_key_field_params = frozendict(min_value=DISK_ID_MIN + 1, max_value=DISK_ID_MAX + 1)
_val_field_class = s.CharField
_val_field_params = frozendict(max_length=64)


class VmMigrateSerializer(s.Serializer):
Expand Down

0 comments on commit 9cfc03c

Please sign in to comment.