
This change enables setting configuration values through environment variables. This is useful to manage user defined configuration, such as user password, in Kubernetes deployment. Change-Id: Iafbb63ebbb388ef3038f45fd3a929c3e7e2dc343
150 lines
4.6 KiB
Python
150 lines
4.6 KiB
Python
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import logging
|
|
import os
|
|
import voluptuous as v
|
|
import yaml
|
|
|
|
from nodepool.driver import ProviderConfig
|
|
from nodepool.config import get_provider_config, substitute_env_vars
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
class ConfigValidator:
|
|
"""Check the layout and certain configuration options"""
|
|
|
|
def __init__(self, config_file):
|
|
self.config_file = config_file
|
|
|
|
@staticmethod
|
|
def getSchema():
|
|
label = {
|
|
'name': str,
|
|
'min-ready': int,
|
|
'max-ready-age': int,
|
|
}
|
|
|
|
diskimage = {
|
|
v.Required('name'): str,
|
|
'abstract': bool,
|
|
'dib-cmd': str,
|
|
'pause': bool,
|
|
'elements': [str],
|
|
'formats': [str],
|
|
'parent': str,
|
|
'release': v.Any(str, int),
|
|
'rebuild-age': int,
|
|
'env-vars': {str: str},
|
|
'username': str,
|
|
'python-path': str,
|
|
'build-timeout': int,
|
|
}
|
|
|
|
webapp = {
|
|
'port': int,
|
|
'listen_address': str,
|
|
}
|
|
|
|
zk_tls = dict(
|
|
cert=v.Required(str),
|
|
key=v.Required(str),
|
|
ca=v.Required(str),
|
|
)
|
|
|
|
top_level = {
|
|
'webapp': webapp,
|
|
'elements-dir': str,
|
|
'images-dir': str,
|
|
'build-log-dir': str,
|
|
'build-log-retention': int,
|
|
'zookeeper-servers': [{
|
|
'host': str,
|
|
'port': int,
|
|
'chroot': str,
|
|
}],
|
|
'zookeeper-tls': zk_tls,
|
|
'providers': list,
|
|
'labels': [label],
|
|
'diskimages': [diskimage],
|
|
'max-hold-age': int,
|
|
}
|
|
return v.Schema(top_level)
|
|
|
|
def validate(self, env=os.environ):
|
|
'''
|
|
Validate a configuration file
|
|
|
|
:return: 0 for success, non-zero for failure
|
|
'''
|
|
provider = ProviderConfig.getCommonSchemaDict()
|
|
|
|
log.info("validating %s" % self.config_file)
|
|
|
|
try:
|
|
with open(self.config_file) as f:
|
|
config = yaml.safe_load(substitute_env_vars(f.read(), env))
|
|
except Exception:
|
|
log.exception('YAML parsing failed')
|
|
return 1
|
|
|
|
self.config = config
|
|
|
|
try:
|
|
# validate the overall schema
|
|
ConfigValidator.getSchema()(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']))
|
|
|
|
diskimages = {}
|
|
for diskimage in config.get('diskimages', []):
|
|
name = diskimage['name']
|
|
if name in diskimages:
|
|
log.error("diskimage %s already defined" % name)
|
|
errors = True
|
|
diskimages[name] = diskimage
|
|
|
|
# Now check every parent is defined
|
|
for diskimage in config.get('diskimages', []):
|
|
if diskimage.get('parent', None):
|
|
if diskimage['parent'] not in diskimages:
|
|
log.error("diskimage %s has non-existant parent: %s" %
|
|
(diskimage['name'], diskimage['parent']))
|
|
errors = True
|
|
|
|
if errors is True:
|
|
return 1
|
|
else:
|
|
return 0
|