Add validation for nodes configs section
Add check for nodes configs section - it should be a dict. Change-Id: Ie0114881aca4f62cfd50ff5358808765aa2924f8
This commit is contained in:
parent
795d58df42
commit
35b7e1f5a7
|
@ -390,10 +390,9 @@ def _create_exports_configmap(exports_map):
|
||||||
|
|
||||||
def _make_topology(nodes, roles, replicas):
|
def _make_topology(nodes, roles, replicas):
|
||||||
failed = False
|
failed = False
|
||||||
# TODO(sreshetniak): move it to validation
|
if not deploy_validation.validate_nodes_section(nodes, CONF.configs):
|
||||||
if not nodes:
|
|
||||||
LOG.error("Nodes section is not specified in configs")
|
|
||||||
failed = True
|
failed = True
|
||||||
|
# TODO(sreshetniak): move it to validation
|
||||||
if not roles:
|
if not roles:
|
||||||
LOG.error("Roles section is not specified in configs")
|
LOG.error("Roles section is not specified in configs")
|
||||||
failed = True
|
failed = True
|
||||||
|
|
|
@ -16,7 +16,9 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from oslotest import base
|
from oslotest import base
|
||||||
|
import six
|
||||||
|
|
||||||
|
from fuel_ccp.config import _yaml
|
||||||
from fuel_ccp.tests import conf_fixture
|
from fuel_ccp.tests import conf_fixture
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,3 +28,12 @@ class TestCase(base.BaseTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestCase, self).setUp()
|
super(TestCase, self).setUp()
|
||||||
self.conf = self.useFixture(conf_fixture.Config()).conf
|
self.conf = self.useFixture(conf_fixture.Config()).conf
|
||||||
|
|
||||||
|
def nested_dict_to_attrdict(self, d):
|
||||||
|
if isinstance(d, dict):
|
||||||
|
return _yaml.AttrDict({k: self.nested_dict_to_attrdict(v)
|
||||||
|
for k, v in six.iteritems(d)})
|
||||||
|
elif isinstance(d, list):
|
||||||
|
return list(map(self.nested_dict_to_attrdict, d))
|
||||||
|
else:
|
||||||
|
return d
|
||||||
|
|
|
@ -1,22 +1,11 @@
|
||||||
import io
|
import io
|
||||||
import jsonschema
|
import jsonschema
|
||||||
import six
|
|
||||||
|
|
||||||
from fuel_ccp import config
|
from fuel_ccp import config
|
||||||
from fuel_ccp.config import _yaml
|
from fuel_ccp.config import _yaml
|
||||||
from fuel_ccp.tests import base
|
from fuel_ccp.tests import base
|
||||||
|
|
||||||
|
|
||||||
def nested_dict_to_attrdict(d):
|
|
||||||
if isinstance(d, dict):
|
|
||||||
return _yaml.AttrDict({k: nested_dict_to_attrdict(v)
|
|
||||||
for k, v in six.iteritems(d)})
|
|
||||||
elif isinstance(d, list):
|
|
||||||
return list(map(nested_dict_to_attrdict, d))
|
|
||||||
else:
|
|
||||||
return d
|
|
||||||
|
|
||||||
|
|
||||||
class TestConfigSchema(base.TestCase):
|
class TestConfigSchema(base.TestCase):
|
||||||
def test_validate_config_schema(self):
|
def test_validate_config_schema(self):
|
||||||
schema = config.get_config_schema()
|
schema = config.get_config_schema()
|
||||||
|
|
|
@ -8,6 +8,7 @@ import yaml
|
||||||
from fuel_ccp.config import _yaml
|
from fuel_ccp.config import _yaml
|
||||||
from fuel_ccp import deploy
|
from fuel_ccp import deploy
|
||||||
from fuel_ccp.tests import base
|
from fuel_ccp.tests import base
|
||||||
|
from fuel_ccp.validation import deploy as deploy_validation
|
||||||
|
|
||||||
|
|
||||||
class TestDeploy(base.TestCase):
|
class TestDeploy(base.TestCase):
|
||||||
|
@ -396,7 +397,7 @@ class TestDeployMakeTopology(base.TestCase):
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
def test_make_empty_topology(self):
|
def test_make_topology_failed(self):
|
||||||
self.assertRaises(RuntimeError,
|
self.assertRaises(RuntimeError,
|
||||||
deploy._make_topology, _yaml.AttrDict(),
|
deploy._make_topology, _yaml.AttrDict(),
|
||||||
_yaml.AttrDict(), _yaml.AttrDict())
|
_yaml.AttrDict(), _yaml.AttrDict())
|
||||||
|
@ -407,6 +408,35 @@ class TestDeployMakeTopology(base.TestCase):
|
||||||
deploy._make_topology,
|
deploy._make_topology,
|
||||||
_yaml.AttrDict({"spam": "eggs"}),
|
_yaml.AttrDict({"spam": "eggs"}),
|
||||||
_yaml.AttrDict(), _yaml.AttrDict())
|
_yaml.AttrDict(), _yaml.AttrDict())
|
||||||
|
self.assertRaises(RuntimeError,
|
||||||
|
deploy._make_topology,
|
||||||
|
self.nested_dict_to_attrdict(
|
||||||
|
{"node1": {"configs": "because-cows"}}),
|
||||||
|
_yaml.AttrDict({"spam": "eggs"}), None)
|
||||||
|
|
||||||
|
def test_nodes_configs_has_new_var(self):
|
||||||
|
nodes = {
|
||||||
|
'node1': {
|
||||||
|
'configs': {
|
||||||
|
'heat': {
|
||||||
|
'stack_params': {
|
||||||
|
'converge_resources': 'True',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
configs = {
|
||||||
|
'heat': {
|
||||||
|
'stack_params': {
|
||||||
|
'debug': True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nodes = self.nested_dict_to_attrdict(nodes)
|
||||||
|
configs = self.nested_dict_to_attrdict(configs)
|
||||||
|
self.assertFalse(deploy_validation.validate_nodes_section(nodes,
|
||||||
|
configs))
|
||||||
|
|
||||||
def test_make_topology_without_replicas(self):
|
def test_make_topology_without_replicas(self):
|
||||||
nodes = _yaml.AttrDict({
|
nodes = _yaml.AttrDict({
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
from fuel_ccp.common import utils
|
from fuel_ccp.common import utils
|
||||||
|
from fuel_ccp.config import _yaml
|
||||||
from fuel_ccp import dependencies
|
from fuel_ccp import dependencies
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def validate_requested_components(components, components_map):
|
def validate_requested_components(components, components_map):
|
||||||
"""Validate requested components.
|
"""Validate requested components.
|
||||||
|
@ -17,3 +22,36 @@ def validate_requested_components(components, components_map):
|
||||||
raise RuntimeError('Following components are also required for '
|
raise RuntimeError('Following components are also required for '
|
||||||
'successful deployment: '
|
'successful deployment: '
|
||||||
'%s' % ' '.join(not_provided_components))
|
'%s' % ' '.join(not_provided_components))
|
||||||
|
|
||||||
|
|
||||||
|
def validate_nodes_section(nodes, configs):
|
||||||
|
valid = True
|
||||||
|
if not nodes:
|
||||||
|
LOG.error("Nodes section is not specified in configs")
|
||||||
|
valid = False
|
||||||
|
else:
|
||||||
|
for name in nodes:
|
||||||
|
if 'configs' in nodes[name]:
|
||||||
|
if not isinstance(nodes[name]['configs'], _yaml.AttrDict):
|
||||||
|
LOG.error("Nodes configs should be a dict, found "
|
||||||
|
"%s" % type(nodes[name]['configs']))
|
||||||
|
valid = False
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
valid = validate_nodes_config(nodes[name]['configs'],
|
||||||
|
configs)
|
||||||
|
if not valid:
|
||||||
|
break
|
||||||
|
return valid
|
||||||
|
|
||||||
|
|
||||||
|
def validate_nodes_config(node_config, global_config):
|
||||||
|
for k in node_config:
|
||||||
|
if k not in global_config:
|
||||||
|
LOG.error('Nodes configs cannot contain new variables, just '
|
||||||
|
'override existent')
|
||||||
|
return False
|
||||||
|
elif (isinstance(node_config[k], (dict, _yaml.AttrDict)) and
|
||||||
|
isinstance(global_config[k], (dict, _yaml.AttrDict))):
|
||||||
|
return validate_nodes_config(node_config[k], global_config[k])
|
||||||
|
return True
|
||||||
|
|
Loading…
Reference in New Issue