Merge "Validate openstack provider pool labels have top-level labels"
This commit is contained in:
commit
5a69b6ad37
@ -27,6 +27,11 @@ class ConfigValidator:
|
|||||||
self.config_file = config_file
|
self.config_file = config_file
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
|
'''
|
||||||
|
Validate a configuration file
|
||||||
|
|
||||||
|
:return: 0 for success, non-zero for failure
|
||||||
|
'''
|
||||||
provider = ProviderConfig.getCommonSchemaDict()
|
provider = ProviderConfig.getCommonSchemaDict()
|
||||||
|
|
||||||
label = {
|
label = {
|
||||||
@ -72,11 +77,42 @@ class ConfigValidator:
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.info("validating %s" % self.config_file)
|
log.info("validating %s" % self.config_file)
|
||||||
config = yaml.safe_load(open(self.config_file))
|
|
||||||
|
|
||||||
# validate the overall schema
|
try:
|
||||||
schema = v.Schema(top_level)
|
config = yaml.safe_load(open(self.config_file))
|
||||||
schema(config)
|
except Exception:
|
||||||
for provider_dict in config.get('providers', []):
|
log.exception('YAML parsing failed')
|
||||||
provider_schema = get_provider_config(provider_dict).getSchema()
|
return 1
|
||||||
provider_schema.extend(provider)(provider_dict)
|
|
||||||
|
try:
|
||||||
|
# validate the overall schema
|
||||||
|
schema = v.Schema(top_level)
|
||||||
|
schema(config)
|
||||||
|
for provider_dict in config.get('providers', []):
|
||||||
|
provider_schema = \
|
||||||
|
get_provider_config(provider_dict).getSchema()
|
||||||
|
provider_schema.extend(provider)(provider_dict)
|
||||||
|
except Exception:
|
||||||
|
log.exception('Schema validation failed')
|
||||||
|
return 1
|
||||||
|
|
||||||
|
errors = False
|
||||||
|
|
||||||
|
# Ensure in openstack provider sections, diskimages have
|
||||||
|
# top-level labels
|
||||||
|
labels = [x['name'] for x in config.get('labels', [])]
|
||||||
|
for provider in config.get('providers', []):
|
||||||
|
if provider.get('driver', 'openstack') != 'openstack':
|
||||||
|
continue
|
||||||
|
for pool in provider.get('pools', []):
|
||||||
|
for label in pool.get('labels', []):
|
||||||
|
if label['name'] not in labels:
|
||||||
|
errors = True
|
||||||
|
log.error("diskimage %s in provider %s "
|
||||||
|
"not in top-level labels" %
|
||||||
|
(label['name'], provider['name']))
|
||||||
|
|
||||||
|
if errors is True:
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
@ -340,8 +340,7 @@ class NodePoolCmd(NodepoolApp):
|
|||||||
|
|
||||||
def config_validate(self):
|
def config_validate(self):
|
||||||
validator = ConfigValidator(self.args.config)
|
validator = ConfigValidator(self.args.config)
|
||||||
validator.validate()
|
return validator.validate()
|
||||||
log.info("Configuration validation complete")
|
|
||||||
# TODO(asselin,yolanda): add validation of secure.conf
|
# TODO(asselin,yolanda): add validation of secure.conf
|
||||||
|
|
||||||
def request_list(self):
|
def request_list(self):
|
||||||
|
@ -366,7 +366,9 @@ class DBTestCase(BaseTestCase):
|
|||||||
self._config_images_dir = images_dir
|
self._config_images_dir = images_dir
|
||||||
self._config_build_log_dir = build_log_dir
|
self._config_build_log_dir = build_log_dir
|
||||||
validator = ConfigValidator(path)
|
validator = ConfigValidator(path)
|
||||||
validator.validate()
|
ret = validator.validate()
|
||||||
|
if ret != 0:
|
||||||
|
raise ValueError("Config file %s could not be validated" % path)
|
||||||
return path
|
return path
|
||||||
|
|
||||||
def replace_config(self, configfile, filename):
|
def replace_config(self, configfile, filename):
|
||||||
|
14
nodepool/tests/fixtures/config_validate/missing_top_label.yaml
vendored
Normal file
14
nodepool/tests/fixtures/config_validate/missing_top_label.yaml
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
# NOTE(mnaser): The trusty label missing here will fail during runtime.
|
||||||
|
labels: []
|
||||||
|
|
||||||
|
providers:
|
||||||
|
- name: static
|
||||||
|
driver: openstack
|
||||||
|
cloud: potato
|
||||||
|
pools:
|
||||||
|
- name: main
|
||||||
|
labels:
|
||||||
|
- name: trusty
|
||||||
|
diskimage: trusty
|
||||||
|
min-ram: 8192
|
@ -16,8 +16,6 @@ import os
|
|||||||
from nodepool.cmd.config_validator import ConfigValidator
|
from nodepool.cmd.config_validator import ConfigValidator
|
||||||
|
|
||||||
from nodepool import tests
|
from nodepool import tests
|
||||||
from yaml.parser import ParserError
|
|
||||||
from voluptuous import MultipleInvalid
|
|
||||||
|
|
||||||
|
|
||||||
class TestConfigValidation(tests.BaseTestCase):
|
class TestConfigValidation(tests.BaseTestCase):
|
||||||
@ -30,14 +28,25 @@ class TestConfigValidation(tests.BaseTestCase):
|
|||||||
'fixtures', 'config_validate', 'good.yaml')
|
'fixtures', 'config_validate', 'good.yaml')
|
||||||
|
|
||||||
validator = ConfigValidator(config)
|
validator = ConfigValidator(config)
|
||||||
validator.validate()
|
ret = validator.validate()
|
||||||
|
self.assertEqual(ret, 0)
|
||||||
|
|
||||||
def test_yaml_error(self):
|
def test_yaml_error(self):
|
||||||
config = os.path.join(os.path.dirname(tests.__file__),
|
config = os.path.join(os.path.dirname(tests.__file__),
|
||||||
'fixtures', 'config_validate', 'yaml_error.yaml')
|
'fixtures', 'config_validate', 'yaml_error.yaml')
|
||||||
|
|
||||||
validator = ConfigValidator(config)
|
validator = ConfigValidator(config)
|
||||||
self.assertRaises(ParserError, validator.validate)
|
ret = validator.validate()
|
||||||
|
self.assertEqual(ret, 1)
|
||||||
|
|
||||||
|
def test_missing_top_level_label(self):
|
||||||
|
config = os.path.join(os.path.dirname(tests.__file__),
|
||||||
|
'fixtures', 'config_validate',
|
||||||
|
'missing_top_label.yaml')
|
||||||
|
|
||||||
|
validator = ConfigValidator(config)
|
||||||
|
ret = validator.validate()
|
||||||
|
self.assertEqual(ret, 1)
|
||||||
|
|
||||||
def test_schema(self):
|
def test_schema(self):
|
||||||
config = os.path.join(os.path.dirname(tests.__file__),
|
config = os.path.join(os.path.dirname(tests.__file__),
|
||||||
@ -45,4 +54,5 @@ class TestConfigValidation(tests.BaseTestCase):
|
|||||||
'schema_error.yaml')
|
'schema_error.yaml')
|
||||||
|
|
||||||
validator = ConfigValidator(config)
|
validator = ConfigValidator(config)
|
||||||
self.assertRaises(MultipleInvalid, validator.validate)
|
ret = validator.validate()
|
||||||
|
self.assertEqual(ret, 1)
|
||||||
|
@ -21,7 +21,6 @@ from nodepool import config as nodepool_config
|
|||||||
from nodepool import tests
|
from nodepool import tests
|
||||||
from nodepool import zk
|
from nodepool import zk
|
||||||
from nodepool.cmd.config_validator import ConfigValidator
|
from nodepool.cmd.config_validator import ConfigValidator
|
||||||
from voluptuous import MultipleInvalid
|
|
||||||
|
|
||||||
|
|
||||||
class TestDriverStatic(tests.DBTestCase):
|
class TestDriverStatic(tests.DBTestCase):
|
||||||
@ -32,7 +31,8 @@ class TestDriverStatic(tests.DBTestCase):
|
|||||||
'fixtures', 'config_validate',
|
'fixtures', 'config_validate',
|
||||||
'static_error.yaml')
|
'static_error.yaml')
|
||||||
validator = ConfigValidator(config)
|
validator = ConfigValidator(config)
|
||||||
self.assertRaises(MultipleInvalid, validator.validate)
|
ret = validator.validate()
|
||||||
|
self.assertEqual(ret, 1)
|
||||||
|
|
||||||
def test_static_config(self):
|
def test_static_config(self):
|
||||||
configfile = self.setup_config('static.yaml')
|
configfile = self.setup_config('static.yaml')
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
import fixtures
|
import fixtures
|
||||||
import voluptuous
|
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from nodepool import config as nodepool_config
|
from nodepool import config as nodepool_config
|
||||||
@ -45,7 +44,7 @@ class TestShadeIntegration(tests.IntegrationTestCase):
|
|||||||
# Assert that we get a nodepool error and not an openstacksdk
|
# Assert that we get a nodepool error and not an openstacksdk
|
||||||
# error.
|
# error.
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
voluptuous.MultipleInvalid,
|
Exception,
|
||||||
self.setup_config, 'integration_noocc.yaml')
|
self.setup_config, 'integration_noocc.yaml')
|
||||||
|
|
||||||
def test_nodepool_occ_config(self):
|
def test_nodepool_occ_config(self):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user