Skip to content

Commit 97e62c0

Browse files
committed
Merge pull request #197 from helgi/dotted
feat(k8s): use dotted format instead of JSON for router domain configuration
2 parents e422469 + ebed321 commit 97e62c0

4 files changed

Lines changed: 53 additions & 67 deletions

File tree

rootfs/api/models.py

Lines changed: 52 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
import logging
1313
import re
1414
import time
15-
import json
1615
import uuid
16+
import morph
1717
from threading import Thread
1818

1919
from django.conf import settings
@@ -1001,40 +1001,61 @@ def _scheduler(self):
10011001
settings.SCHEDULER_AUTH,
10021002
settings.SCHEDULER_OPTIONS)
10031003

1004-
def _load_service_config(self, app):
1004+
def _fetch_service_config(self, app):
10051005
# Get the service from k8s to attach the domain correctly
10061006
svc = self._scheduler._get_service(app, app).json()
10071007
# Get minimum structure going if it is missing on the service
10081008
if 'metadata' not in svc or 'annotations' not in svc['metadata']:
10091009
default = {'metadata': {'annotations': {}}}
10101010
svc = dict_merge(svc, default)
10111011

1012-
# Check if any config has been set
1013-
if 'deis.io/routerConfig' not in svc['metadata']['annotations']:
1014-
config = {}
1015-
else:
1016-
config = json.loads(svc['metadata']['annotations']['deis.io/routerConfig'])
1012+
return svc
10171013

1018-
# See if domains are available
1019-
if 'domains' not in config:
1020-
config['domains'] = []
1014+
def _load_service_config(self, app, component):
1015+
# fetch setvice definition with minimum structure
1016+
svc = self._fetch_service_config(app)
1017+
1018+
# always assume a .deis.io/ ending
1019+
component = "%s.deis.io/" % component
1020+
1021+
# Filter to only include values for the component and strip component out of it
1022+
# Processes dots into a nested structure
1023+
config = morph.unflatten(morph.pick(svc['metadata']['annotations'], prefix=component))
1024+
1025+
return config
10211026

1022-
return svc, config
1027+
def _save_service_config(self, app, component, data):
1028+
# fetch setvice definition with minimum structure
1029+
svc = self._fetch_service_config(app)
1030+
1031+
# always assume a .deis.io ending
1032+
component = "%s.deis.io/" % component
1033+
1034+
# add component to data and flatten
1035+
data = {"%s%s" % (component, key): value for key, value in data.items()}
1036+
svc['metadata']['annotations'].update(morph.flatten(data))
1037+
1038+
# Update the k8s service for the application with new domain information
1039+
self._scheduler._update_service(app, app, svc)
10231040

10241041
def save(self, *args, **kwargs):
10251042
app = str(self.app)
10261043
domain = str(self.domain)
10271044

1028-
# setup the service and config dict
1029-
svc, config = self._load_service_config(app)
1030-
if domain not in config['domains']:
1031-
config['domains'].append(domain)
1045+
# get annotations for the service
1046+
config = self._load_service_config(app, 'router')
10321047

1033-
# save as a JSON string since annotations don't take a structure on its keys
1034-
svc['metadata']['annotations']['deis.io/routerConfig'] = json.dumps(config)
1048+
# See if domains are available
1049+
if 'domains' not in config:
1050+
config['domains'] = ''
10351051

1036-
# Update the k8s service for the application with new domain information
1037-
self._scheduler._update_service(app, app, svc)
1052+
# convert from string to list to work with and filter out empty strings
1053+
domains = filter(None, config['domains'].split(','))
1054+
if domain not in domains:
1055+
domains.append(domain)
1056+
config['domains'] = ','.join(domains)
1057+
1058+
self._save_service_config(app, 'router', config)
10381059

10391060
# Save to DB
10401061
return super(Domain, self).save(*args, **kwargs)
@@ -1043,16 +1064,20 @@ def delete(self, *args, **kwargs):
10431064
app = str(self.app)
10441065
domain = str(self.domain)
10451066

1046-
# setup the service and config dict
1047-
svc, config = self._load_service_config(app)
1048-
if domain in config['domains']:
1049-
config['domains'].remove(domain)
1067+
# get annotations for the service
1068+
config = self._load_service_config(app, 'router')
10501069

1051-
# save as a JSON string since annotations don't take a structure on its keys
1052-
svc['metadata']['annotations']['deis.io/routerConfig'] = json.dumps(config)
1070+
# See if domains are available
1071+
if 'domains' not in config:
1072+
config['domains'] = ''
10531073

1054-
# Update the k8s service for the application with new domain information
1055-
self._scheduler._update_service(app, app, svc)
1074+
# convert from string to list to work with and filter out empty strings
1075+
domains = filter(None, config['domains'].split(','))
1076+
if domain in domains:
1077+
domains.remove(domain)
1078+
config['domains'] = ','.join(domains)
1079+
1080+
self._save_service_config(app, 'router', config)
10561081

10571082
# Delete from DB
10581083
return super(Domain, self).delete(*args, **kwargs)

rootfs/api/utils.py

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -141,26 +141,6 @@ def dict_merge(origin, merge):
141141
return result
142142

143143

144-
def flatten(collection):
145-
"""
146-
Flatten an arbitrarily deep structure of dicts, lists and tuples and
147-
extract the strings at the leaves of the structures.
148-
"""
149-
vals = []
150-
if isinstance(collection, basestring):
151-
vals.append(collection)
152-
elif isinstance(collection, (list, tuple)):
153-
for item in collection:
154-
vals.extend(flatten(item))
155-
elif isinstance(collection, dict):
156-
vals.extend(flatten(collection.values()))
157-
else:
158-
raise Exception(
159-
"Can't extract values from a %s" % collection.__class__
160-
)
161-
return vals
162-
163-
164144
if __name__ == "__main__":
165145
import doctest
166146
doctest.testmod()

rootfs/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ PyYAML==3.11
1313
requests==2.8.1
1414
simpleflock==0.0.2
1515
static==1.1.1
16+
morph==0.1.2

rootfs/scheduler/utils.py

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -31,23 +31,3 @@ def dict_merge(origin, merge):
3131
else:
3232
result[key] = deepcopy(value)
3333
return result
34-
35-
36-
def flatten(collection):
37-
"""
38-
Flatten an arbitrarily deep structure of dicts, lists and tuples and
39-
extract the strings at the leaves of the structures.
40-
"""
41-
vals = []
42-
if isinstance(collection, basestring):
43-
vals.append(collection)
44-
elif isinstance(collection, (list, tuple)):
45-
for item in collection:
46-
vals.extend(flatten(item))
47-
elif isinstance(collection, dict):
48-
vals.extend(flatten(collection.values()))
49-
else:
50-
raise Exception(
51-
"Can't extract values from a %s" % collection.__class__
52-
)
53-
return vals

0 commit comments

Comments
 (0)