nodepool/nodepool/config.py
David Shrewsbury 477a40044b Add support for a secure ZooKeeper configuration
The secure config file has largely been unused and ignored for v3.
This add support for reading ZooKeeper credentials from the secure
file. Note that actually specifying authentication credentials is
left for future work, but this adds the framework necessary for that.

ZooKeeper creds can be in both the normal config file and the secure
file. If specified in both, the data in the secure configuration wins.

Change-Id: I5d9c12c00f5e85ef258128337cdb99809f86b8ed
2018-01-09 16:03:33 -05:00

169 lines
5.5 KiB
Python
Executable File

#!/usr/bin/env python
# Copyright (C) 2011-2013 OpenStack Foundation
#
# 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 time
import yaml
from nodepool import zk
from nodepool.driver import ConfigValue
from nodepool.driver.fake.config import FakeProviderConfig
from nodepool.driver.openstack.config import OpenStackProviderConfig
class Config(ConfigValue):
pass
class Label(ConfigValue):
def __repr__(self):
return "<Label %s>" % self.name
class DiskImage(ConfigValue):
def __eq__(self, other):
if (other.name != self.name or
other.elements != self.elements or
other.release != self.release or
other.rebuild_age != self.rebuild_age or
other.env_vars != self.env_vars or
other.image_types != self.image_types or
other.pause != self.pause or
other.username != self.username):
return False
return True
def __ne__(self, other):
return not self.__eq__(other)
def __repr__(self):
return "<DiskImage %s>" % self.name
def get_provider_config(provider):
provider.setdefault('driver', 'openstack')
# Ensure legacy configuration still works when using fake cloud
if provider.get('name', '').startswith('fake'):
provider['driver'] = 'fake'
if provider['driver'] == 'fake':
return FakeProviderConfig(provider)
elif provider['driver'] == 'openstack':
return OpenStackProviderConfig(provider)
def openConfig(path):
retry = 3
# Since some nodepool code attempts to dynamically re-read its config
# file, we need to handle the race that happens if an outside entity
# edits it (causing it to temporarily not exist) at the same time we
# attempt to reload it.
while True:
try:
config = yaml.load(open(path))
break
except IOError as e:
if e.errno == 2:
retry = retry - 1
time.sleep(.5)
else:
raise e
if retry == 0:
raise e
return config
def loadConfig(config_path):
config = openConfig(config_path)
# Reset the shared os_client_config instance
OpenStackProviderConfig.os_client_config = None
newconfig = Config()
newconfig.db = None
newconfig.webapp = {
'port': config.get('webapp', {}).get('port', 8005),
'listen_address': config.get('webapp', {}).get('listen_address',
'0.0.0.0')
}
newconfig.providers = {}
newconfig.labels = {}
newconfig.elementsdir = config.get('elements-dir')
newconfig.imagesdir = config.get('images-dir')
newconfig.provider_managers = {}
newconfig.zookeeper_servers = {}
newconfig.diskimages = {}
for server in config.get('zookeeper-servers', []):
z = zk.ZooKeeperConnectionConfig(server['host'],
server.get('port', 2181),
server.get('chroot', None))
name = z.host + '_' + str(z.port)
newconfig.zookeeper_servers[name] = z
for diskimage in config.get('diskimages', []):
d = DiskImage()
d.name = diskimage['name']
newconfig.diskimages[d.name] = d
if 'elements' in diskimage:
d.elements = u' '.join(diskimage['elements'])
else:
d.elements = ''
# must be a string, as it's passed as env-var to
# d-i-b, but might be untyped in the yaml and
# interpreted as a number (e.g. "21" for fedora)
d.release = str(diskimage.get('release', ''))
d.rebuild_age = int(diskimage.get('rebuild-age', 86400))
d.env_vars = diskimage.get('env-vars', {})
if not isinstance(d.env_vars, dict):
d.env_vars = {}
d.image_types = set(diskimage.get('formats', []))
d.pause = bool(diskimage.get('pause', False))
d.username = diskimage.get('username', 'zuul')
for label in config.get('labels', []):
l = Label()
l.name = label['name']
newconfig.labels[l.name] = l
l.max_ready_age = label.get('max-ready-age', 0)
l.min_ready = label.get('min-ready', 2)
l.pools = []
for provider in config.get('providers', []):
p = get_provider_config(provider)
p.load(newconfig)
newconfig.providers[p.name] = p
return newconfig
def loadSecureConfig(config, secure_config_path):
secure = openConfig(secure_config_path)
if not secure: # empty file
return
# Eliminate any servers defined in the normal config
if secure.get('zookeeper-servers', []):
config.zookeeper_servers = {}
# TODO(Shrews): Support ZooKeeper auth
for server in secure.get('zookeeper-servers', []):
z = zk.ZooKeeperConnectionConfig(server['host'],
server.get('port', 2181),
server.get('chroot', None))
name = z.host + '_' + str(z.port)
config.zookeeper_servers[name] = z