Skip to content

Commit 0a518d6

Browse files
committed
fix(controller): specify dicts as defaults and guard against old errors
We should have been initializing our JSONFields with dict objects, not strings. Also upgrading from a slightly earlier version of Deis to this change could hit a JSON encoding error, so catch that and use the chance to clean up the data. Also reverted the unnecessary workaround of subclassing JSONField.
1 parent 4a0ad8d commit 0a518d6

4 files changed

Lines changed: 22 additions & 32 deletions

File tree

controller/api/fields.py

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,6 @@
88
from django import forms
99
from django.db import models
1010

11-
import json_field
12-
13-
14-
class JSONField(json_field.JSONField):
15-
16-
"""
17-
A subclass of json_field.JSONField that fixes empty JSON object
18-
encoding behavior.
19-
"""
20-
21-
def get_db_prep_value(self, value, *args, **kwargs):
22-
# if it's one of these values, it's already encoded
23-
if value in ['{}', '[]']:
24-
return value
25-
return super(JSONField, self).get_db_prep_value(value, *args, **kwargs)
26-
2711

2812
class UuidField(models.CharField):
2913
"""A univerally unique ID field."""

controller/api/models.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from django.utils.encoding import python_2_unicode_compatible
2222
from django_fsm import FSMField, transition
2323
from django_fsm.signals import post_transition
24+
from json_field.fields import JSONField
2425

2526
from api import fields, tasks
2627
from registry import publish_release
@@ -87,7 +88,7 @@ class Cluster(UuidAuditedModel):
8788
domain = models.CharField(max_length=128)
8889
hosts = models.CharField(max_length=256)
8990
auth = models.TextField()
90-
options = fields.JSONField(default='{}', blank=True)
91+
options = JSONField(default={}, blank=True)
9192

9293
def __str__(self):
9394
return self.id
@@ -122,7 +123,7 @@ class App(UuidAuditedModel):
122123
owner = models.ForeignKey(settings.AUTH_USER_MODEL)
123124
id = models.SlugField(max_length=64, unique=True)
124125
cluster = models.ForeignKey('Cluster')
125-
structure = fields.JSONField(default='{}', blank=True)
126+
structure = JSONField(default={}, blank=True)
126127

127128
class Meta:
128129
permissions = (('use_app', 'Can use app'),)
@@ -135,7 +136,7 @@ def url(self):
135136
return self.id + '.' + self.cluster.domain
136137

137138
def create(self, *args, **kwargs):
138-
config = Config.objects.create(owner=self.owner, app=self, values={})
139+
config = Config.objects.create(owner=self.owner, app=self)
139140
build = Build.objects.create(owner=self.owner, app=self, image=settings.DEFAULT_BUILD)
140141
Release.objects.create(version=1, owner=self.owner, app=self, config=config, build=build)
141142

@@ -407,7 +408,7 @@ class Build(UuidAuditedModel):
407408

408409
# optional fields populated by builder
409410
sha = models.CharField(max_length=40, blank=True)
410-
procfile = fields.JSONField(default='{}', blank=True)
411+
procfile = JSONField(default={}, blank=True)
411412
dockerfile = models.TextField(blank=True)
412413

413414
class Meta:
@@ -428,9 +429,9 @@ class Config(UuidAuditedModel):
428429

429430
owner = models.ForeignKey(settings.AUTH_USER_MODEL)
430431
app = models.ForeignKey('App')
431-
values = fields.JSONField(default='{}', blank=True)
432-
memory = fields.JSONField(default='{}', blank=True)
433-
cpu = fields.JSONField(default='{}', blank=True)
432+
values = JSONField(default={}, blank=True)
433+
memory = JSONField(default={}, blank=True)
434+
cpu = JSONField(default={}, blank=True)
434435

435436
class Meta:
436437
get_latest_by = 'created'

controller/api/south_migrations/0013_auto__del_limit__del_unique_limit_app_uuid__del_field_config_limit__ad.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ def forwards(self, orm):
1919

2020
# Adding field 'Config.memory'
2121
db.add_column(u'api_config', 'memory',
22-
self.gf('json_field.fields.JSONField')(default=u'{}', blank=True),
22+
self.gf('json_field.fields.JSONField')(default={}, blank=True),
2323
keep_default=False)
2424

2525
# Adding field 'Config.cpu'
2626
db.add_column(u'api_config', 'cpu',
27-
self.gf('json_field.fields.JSONField')(default=u'{}', blank=True),
27+
self.gf('json_field.fields.JSONField')(default={}, blank=True),
2828
keep_default=False)
2929

3030

@@ -63,7 +63,7 @@ def backwards(self, orm):
6363
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
6464
'id': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '64'}),
6565
'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
66-
'structure': ('json_field.fields.JSONField', [], {'default': "u'{}'", 'blank': 'True'}),
66+
'structure': ('json_field.fields.JSONField', [], {'default': '{}', 'blank': 'True'}),
6767
'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
6868
'uuid': ('api.fields.UuidField', [], {'unique': 'True', 'max_length': '32', 'primary_key': 'True'})
6969
},
@@ -74,7 +74,7 @@ def backwards(self, orm):
7474
'dockerfile': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
7575
'image': ('django.db.models.fields.CharField', [], {'max_length': '256'}),
7676
'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
77-
'procfile': ('json_field.fields.JSONField', [], {'default': "u'{}'", 'blank': 'True'}),
77+
'procfile': ('json_field.fields.JSONField', [], {'default': '{}', 'blank': 'True'}),
7878
'sha': ('django.db.models.fields.CharField', [], {'max_length': '40', 'blank': 'True'}),
7979
'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
8080
'uuid': ('api.fields.UuidField', [], {'unique': 'True', 'max_length': '32', 'primary_key': 'True'})
@@ -86,7 +86,7 @@ def backwards(self, orm):
8686
'domain': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
8787
'hosts': ('django.db.models.fields.CharField', [], {'max_length': '256'}),
8888
'id': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'}),
89-
'options': ('json_field.fields.JSONField', [], {'default': "u'{}'", 'blank': 'True'}),
89+
'options': ('json_field.fields.JSONField', [], {'default': '{}', 'blank': 'True'}),
9090
'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
9191
'type': ('django.db.models.fields.CharField', [], {'default': "u'coreos'", 'max_length': '16'}),
9292
'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
@@ -95,13 +95,13 @@ def backwards(self, orm):
9595
u'api.config': {
9696
'Meta': {'ordering': "[u'-created']", 'unique_together': "((u'app', u'uuid'),)", 'object_name': 'Config'},
9797
'app': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['api.App']"}),
98-
'cpu': ('json_field.fields.JSONField', [], {'default': "u'{}'", 'blank': 'True'}),
98+
'cpu': ('json_field.fields.JSONField', [], {'default': '{}', 'blank': 'True'}),
9999
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
100-
'memory': ('json_field.fields.JSONField', [], {'default': "u'{}'", 'blank': 'True'}),
100+
'memory': ('json_field.fields.JSONField', [], {'default': '{}', 'blank': 'True'}),
101101
'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
102102
'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
103103
'uuid': ('api.fields.UuidField', [], {'unique': 'True', 'max_length': '32', 'primary_key': 'True'}),
104-
'values': ('json_field.fields.JSONField', [], {'default': "u'{}'", 'blank': 'True'})
104+
'values': ('json_field.fields.JSONField', [], {'default': '{}', 'blank': 'True'})
105105
},
106106
u'api.container': {
107107
'Meta': {'ordering': "[u'created']", 'object_name': 'Container'},

controller/api/views.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,12 @@ def create(self, request, *args, **kwargs):
396396
obj = self.get_object()
397397
request.DATA['app'] = obj.app
398398
for attr in ['cpu', 'memory', 'values']:
399-
data = getattr(obj, attr).copy()
399+
# Guard against migrations from older apps without fixes to
400+
# JSONField encoding.
401+
try:
402+
data = getattr(obj, attr).copy()
403+
except AttributeError:
404+
data = {}
400405
if attr in request.DATA:
401406
# merge config values
402407
provided = json.loads(request.DATA[attr])

0 commit comments

Comments
 (0)