Unverified Commit 03b60b9a authored by Michal 'vorner' Vaner's avatar Michal 'vorner' Vaner
Browse files

Merge #2113

parents 4f9f077f b4dc5098
......@@ -16,20 +16,64 @@
from isc.config.module_spec import module_spec_from_file
from isc.util.file import path_search
from bind10_config import PLUGIN_PATHS
import isc.dns
import isc.datasrc
import json
import os.path
import copy
spec = module_spec_from_file(path_search('datasrc.spec', PLUGIN_PATHS))
def check(config):
"""
Check the configuration.
"""
# TODO: Once we have solved ticket #2051, create the list and
# fill it with the configuration. We probably want to have some way
# to not load the data sources, just the configuration. It could
# be hacked together by subclassing ConfigurableClientList and
# having empty getDataSource method. But it looks like a hack and it
# won't really check the params configuration.
#
# For now, we let everything pass.
# Check the data layout first
errors=[]
if not spec.validate_config(False, config, errors):
return ' '.join(errors)
classes = config.get('classes')
# Nothing passed here
if classes is None:
return None
for rr_class_str in classes:
try:
rr_class = isc.dns.RRClass(rr_class_str)
except isc.dns.InvalidRRClass as irc:
return "The class '" + rr_class_str + "' is invalid"
dlist = isc.datasrc.ConfigurableClientList(rr_class)
# We get a copy here, as we are going to mangle the configuration.
# But we don't want our changes to propagate outside, to the real
# configuration.
client_config = copy.deepcopy(classes.get(rr_class_str))
for client in client_config:
if client['type'] == 'MasterFiles':
if not client.get('cache-enable', False):
return 'The cache must be enabled in MasterFiles type'
params = client.get('params')
if type(params) != dict:
return 'Params of MasterFiles must be a named set'
for name in params:
try:
isc.dns.Name(name)
except Exception as e: # There are many related exceptions
return str(e)
if not os.path.exists(params[name]):
return "Master file " + params[name] + " does not exist"
# We remove the list of zones locally. We already checked them,
# and the client list would have skipped them anyway, as we
# forbid cache. But it would produce a warning and we don't
# want that here.
client['params'] = {}
try:
dlist.configure(json.dumps(client_config), False)
except isc.datasrc.Error as dse:
return str(dse)
return None
def load():
......
......@@ -16,12 +16,36 @@
# Make sure we can load the module, put it into path
import sys
import os
import unittest
import json
sys.path.extend(os.environ["B10_TEST_PLUGIN_DIR"].split(':'))
import isc.log
import datasrc_config_plugin
import unittest
class DatasrcTest(unittest.TestCase):
def reject(self, config):
"""
Just a shortcut to check the config is rejected.
"""
old = json.dumps(config)
self.assertIsNotNone(datasrc_config_plugin.check({"classes":
config}))
# There's some data mangling inside the plugin. Check it does
# not propagate out, as it could change the real configuration.
self.assertEqual(old, json.dumps(config))
def accept(self, config):
"""
Just a shortcut to check the config is accepted.
"""
old = json.dumps(config)
self.assertIsNone(datasrc_config_plugin.check({"classes":
config}))
# There's some data mangling inside the plugin. Check it does
# not propagate out, as it could change the real configuration.
self.assertEqual(old, json.dumps(config))
def test_load(self):
"""
Checks the entry point returns the correct values.
......@@ -32,5 +56,104 @@ class DatasrcTest(unittest.TestCase):
# The plugin stores it's spec
self.assertEqual(spec, datasrc_config_plugin.spec)
def test_empty(self):
"""
Check an empty input is OK.
"""
self.accept({})
def test_invalid_spec(self):
"""
Check it rejects stuff that is not well-formed according
to the spec.
"""
self.reject("test")
self.reject(13)
self.reject([])
self.reject({"IN": {}})
self.reject({"IN": [{"bad-name": True}]})
def test_class(self):
"""
The class is rejected, if it is wrong.
"""
self.reject({"BAD": []})
self.reject({"": []})
# But with a good one, it works
for c in ["IN", "CH", "HS"]:
self.accept({c: []})
def test_mem_ok(self):
"""
Test we accept an in-memory data source. It doesn't really matter
which one it is. We just want to make sure we accept something
and this one does not need any kind of path mangling to find
plugins.
"""
self.accept({"IN": [{
"type": "MasterFiles",
"cache-enable": True,
"params": {}
}]})
def test_dstype_bad(self):
"""
The configuration is correct by the spec, but it would be rejected
by the client list. Check we reject it.
"""
self.reject({"IN": [{
"type": "No such type"
}]})
def test_invalid_mem_params(self):
"""
The client list skips in-memory sources. So we check it locally that
invalid things are rejected.
"""
# The 'params' key is mandatory for MasterFiles
self.reject({"IN": [{
"type": "MasterFiles",
"cache-enable": True
}]})
# The cache must be enabled
self.reject({"IN": [{
"type": "MasterFiles",
"cache-enable": False,
"params": {}
}]})
self.reject({"IN": [{
"type": "MasterFiles",
"params": {}
}]})
# Bad params type
self.reject({"IN": [{
"type": "MasterFiles",
"cache-enable": True,
"params": []
}]})
# Bad name
self.reject({"IN": [{
"type": "MasterFiles",
"cache-enable": True,
"params": {
"example....org.": '/file/does/not/exist'
}
}]})
def test_no_such_file_mem(self):
"""
We also check the existance of master files. Not the actual content,
though.
"""
self.reject({"IN": [{
"type": "MasterFiles",
"cache-enable": True,
"params": {
"example.org.": '/file/does/not/exist'
}
}]})
if __name__ == '__main__':
unittest.main()
isc.log.init("bind10")
isc.log.resetUnitTestRootLogger()
unittest.main()
......@@ -386,6 +386,8 @@ def _validate_format(spec, value, errors):
return True
def _validate_item(spec, full, data, errors):
if spec.get('item_type') == 'any':
return True
if not _validate_type(spec, data, errors):
return False
elif type(data) == list:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment