summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <lars.wirzenius@codethink.co.uk>2014-03-26 16:47:51 +0000
committerLars Wirzenius <lars.wirzenius@codethink.co.uk>2014-03-26 16:47:51 +0000
commitf5e856e41f5b360cecc9314178fe2bc6e60766b4 (patch)
tree995e1d8808dbd11036ee497d0f8362ead73e7ff6
parent1d04f87b31a03930bcbc96c8bf7f8a9d6b7075b4 (diff)
downloadlorry-controller-f5e856e41f5b360cecc9314178fe2bc6e60766b4.tar.gz
Add rudimentary validation
-rw-r--r--lorrycontroller/readconf.py43
-rw-r--r--yarns.webapp/060-validation.yarn12
-rw-r--r--yarns.webapp/900-implementations.yarn28
3 files changed, 83 insertions, 0 deletions
diff --git a/lorrycontroller/readconf.py b/lorrycontroller/readconf.py
index 64599e4..cd89a49 100644
--- a/lorrycontroller/readconf.py
+++ b/lorrycontroller/readconf.py
@@ -48,6 +48,11 @@ class ReadConfiguration(lorrycontroller.LorryControllerRoute):
conf_obj = self.read_config_file()
except LorryControllerConfParseError as e:
return str(e)
+
+ error = self.validate_config(conf_obj)
+ if error:
+ return 'ERROR: %s: %r' % (error, conf_obj)
+
self.fix_up_parsed_fields(conf_obj)
statedb = self.open_statedb()
@@ -130,6 +135,10 @@ class ReadConfiguration(lorrycontroller.LorryControllerRoute):
except ValueError as e:
raise LorryControllerConfParseError(filename, e)
+ def validate_config(self, obj):
+ validator = LorryControllerConfValidator()
+ return validator.validate_config(obj)
+
def fix_up_parsed_fields(self, obj):
for item in obj:
item['interval'] = self.fix_up_interval(item.get('interval'))
@@ -220,3 +229,37 @@ class ReadConfiguration(lorrycontroller.LorryControllerRoute):
ls_interval=section['ls-interval'],
prefixmap=json.dumps(section['prefixmap']),
ignore=json.dumps(section['ignore']))
+
+
+class LorryControllerConfValidator(object):
+
+ def validate_config(self, conf_obj):
+ for check in self._find_checks():
+ error = check(conf_obj)
+ if error:
+ return error
+ return None
+
+ def _find_checks(self):
+ return [
+ getattr(self, name)
+ for name in dir(self)
+ if name.startswith('_check_')]
+
+ def _check_is_list(self, conf_obj):
+ if type(conf_obj) is not list:
+ return 'is not a JSON list'
+
+ def _check_is_list_of_dicts(self, conf_obj):
+ for item in conf_obj:
+ if type(item) is not dict:
+ return 'all items must be dicts'
+
+ def _check_sections_have_known_type(self, conf_obj):
+ allowed_types = ['lorries', 'trove', 'troves']
+
+ for item in conf_obj:
+ if 'type' not in conf_obj:
+ return 'must have a type field'
+ if conf_obj['type'] not in allowed_types:
+ return ('must have a known type, not %r' % conf_obj['type'])
diff --git a/yarns.webapp/060-validation.yarn b/yarns.webapp/060-validation.yarn
index b7b1a66..4d2ce3b 100644
--- a/yarns.webapp/060-validation.yarn
+++ b/yarns.webapp/060-validation.yarn
@@ -83,6 +83,18 @@ non-sensical value?
THEN response matches "ERROR"
AND STATEDB is empty
+Now we're getting to real sections. A `troves` section must have
+`trovehost`, `interval`, `ls-interval`, and `prefixmap` set, and may
+optionally have `ignore` set. Test each of those with good and bad
+values.
+
+ GIVEN an empty lorry-controller.conf in CONFGIT
+ AND lorry-controller.conf in CONFGIT adds trove example-trove
+ AND lorry-controller.conf in CONFGIT sets interval to "blah" for trove example-trove
+ WHEN admin makes request POST /1.0/read-configuration with dummy=value
+ THEN response matches "ERROR"
+ AND STATEDB is empty
+
Clean up at the end.
FINALLY WEBAPP terminates
diff --git a/yarns.webapp/900-implementations.yarn b/yarns.webapp/900-implementations.yarn
index c88b6fa..39c4a63 100644
--- a/yarns.webapp/900-implementations.yarn
+++ b/yarns.webapp/900-implementations.yarn
@@ -173,6 +173,34 @@ most of the configuration.
json.dump(obj, f, indent=4)
'
+Set a specific field for a `troves` section.
+
+ IMPLEMENTS GIVEN (\S+) in (\S+) sets (\S+) to (\S+) for trove (\S+)
+ python -c '
+ import os
+ import json
+
+ DATADIR = os.environ["DATADIR"]
+ MATCH_1 = os.environ["MATCH_1"]
+ MATCH_2 = os.environ["MATCH_2"]
+ MATCH_3 = os.environ["MATCH_3"]
+ MATCH_4 = os.environ["MATCH_3"]
+ MATCH_5 = os.environ["MATCH_3"]
+
+ filename = os.path.join(DATADIR, MATCH_2, MATCH_1)
+
+ with open(filename, "r") as f:
+ obj = json.load(f)
+
+ for section in obj:
+ if section["type"] in ["trove", "troves"]:
+ if section["trovehost"] == MATCH_5:
+ section[MATCH_3] = json.loads(MATCH_4)
+
+ with open(filename, "w") as f:
+ json.dump(obj, f, indent=4)
+ '
+
Set the prefixmap for a Trove in a Lorry Controller configuration
file. Note that the Trove must already be in the configuration file.