Replace config-external with a JSON file

Replace config-external with JSON file. The JSON file will
be placed in each of the services directories with expected
location and destination.

Set-configs.py will be responsible for interpreting the JSON file,
creating the necessary directories, moving config files, and
and providing a command line for start.sh to run the service
with the correct config files specified.

Partially-Implements: blueprint replace-config-external
Change-Id: I5e2e69dfe3ae7f938fcf51f1cd450aaa10e7f1e3
This commit is contained in:
rthallisey 2015-08-25 17:41:57 -04:00 committed by Ryan Hallisey
parent f1abd86665
commit 3d7f9fd624
2 changed files with 219 additions and 1 deletions

View File

@ -205,4 +205,4 @@ RUN apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com 199369E5404BD
{% endif %}
COPY kolla-common.sh /opt/kolla/
COPY set_configs.py kolla-common.sh /opt/kolla/

218
docker/base/set_configs.py Normal file
View File

@ -0,0 +1,218 @@
#!/usr/bin/env 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 json
import logging
import os
from pwd import getpwnam
import shutil
import sys
# TODO(rhallisey): add docstring.
logging.basicConfig()
LOG = logging.getLogger(__name__)
LOG.setLevel(logging.INFO)
def json_key_validation(json_file):
valid_keys = ['source', 'dest', 'owner', 'perm']
# 'command' is not present in the json file
if json_file.get('command') is None:
LOG.error('command was never specified in your json file. Command '
'is what your container will execute upon start.')
sys.exit(1)
# Check for valid keys
for data in json_file.get('config_files'):
key_not_found = ''
for valid_key in valid_keys:
if valid_key not in data.keys():
key_not_found += valid_key + ' '
if key_not_found is not '':
LOG.error('JSON data "%s" is missing keys "%s"'
% (data.keys(), key_not_found))
sys.exit(1)
for key in data.keys():
# Invalid key in json file
if key not in valid_keys:
LOG.error('Unexpected JSON key "%s". This value is currently '
'not supported.' % key)
sys.exit(1)
# The command option will be built up and written to '/command_options'.
# which will be added to the end of $CMD in start.sh as $ARGS.
def write_command_options(args):
with open('/command_options', 'w+') as f:
f.write(args)
def copy_configurations():
json_path = '/opt/kolla/config_files/config.json'
LOG.info('Loading config json file "%s".' % json_path)
# If JSON file is empty don't move any configs.
# It's required there always be at least 'command' in the json file
with open(json_path) as conf:
try:
config = json.load(conf)
except ValueError:
LOG.error('Empty config json file present. There are no config '
'files being moved.')
sys.exit(1)
json_key_validation(config)
# Save the 'command' specified in the json file so start.sh can
# consume it.
cmd = config.get('command')
write_command_options(cmd)
for data in config.get('config_files'):
dest_path = data.get('dest')
source_path = data.get('source')
config_owner = data.get('owner')
LOG.info('The command being run is "%s"' % cmd)
# Make sure all the proper config dirs are in place.
if os.path.isdir(dest_path):
# The destination is a dir
LOG.info('Checking if parent directories for "%s" exist.'
% dest_path)
else:
# The destination is a file
dest_path = os.path.dirname(data.get('dest'))
LOG.info('Checking if parent directories for "%s" exist.'
% dest_path)
if os.path.exists(dest_path):
LOG.info('Config destination "%s" has the proper directories '
'in place.' % dest_path)
else:
os.makedirs(dest_path)
LOG.info('Creating directory "%s" because it was not found.'
% dest_path)
# Copy over the config file(s).
if os.path.isdir(source_path):
# The source is a dir
LOG.info('Checking if there are any config files mounted '
'in "%s".' % source_path)
config_files = os.listdir(source_path)
if config_files == []:
LOG.warning('The source directory "%s" is empty. No '
'config files will be copied.'
% source_path)
else:
# Source and dest need to either both be dirs or files
if os.path.isdir(dest_path):
for config in config_files:
shutil.copy(config, dest_path)
LOG.info('Config file found. Copying config file '
'"%s" to "%s".'
% (config, dest_path))
else:
LOG.error('If you specify the config source as a '
'directory, then the destination also needs '
'to be a directory')
sys.exit(1)
else:
# The source is a file
LOG.info('Checking if there is a config file mounted in "%s".'
% (source_path))
if os.path.exists(source_path):
shutil.copy(source_path, dest_path)
LOG.info('Config file found. Copying config file "%s" to '
'"%s".' % (source_path, dest_path))
if dest_path in cmd:
LOG.info('Using config file: "%s" to start the %s '
'service'
% (source_path, config_owner))
else:
LOG.warning('The config file "%s" is present, but you '
'are not using it when starting %s. '
% (source_path, config_owner))
else:
LOG.warning('Skipping config "%s" because it was not '
'mounted at the expected location: "%s".'
% (dest_path, source_path))
# Check for user and group id in the environment.
try:
uid = getpwnam(config_owner).pw_uid
except KeyError:
LOG.error('The user "%s" does not exist.'
% config_owner)
sys.exit(1)
try:
gid = getpwnam(config_owner).pw_gid
except KeyError:
LOG.error('The group "%s" doesn\'t exist.'
% config_owner)
sys.exit(1)
# Give config file proper perms.
try:
os.chown(dest_path, uid, gid)
except OSError as e:
LOG.error("Couldn't chown file %s because of"
"os error %s." % (dest_path, e))
sys.exit(1)
try:
os.chmod(dest_path, int(data.get('perm')))
except OSError as e:
LOG.error("Couldn't chown file %s because of"
"os error %s." % (dest_path, e))
sys.exit(1)
def execute_config_strategy():
try:
kolla_config_strategy = os.environ.get("KOLLA_CONFIG_STRATEGY")
except KeyError:
LOG.error("KOLLA_CONFIG_STRATEGY is not set properly.")
sys.exit(1)
if kolla_config_strategy == "COPY_ALWAYS":
# Read all existing json files.
copy_configurations()
elif kolla_config_strategy == "COPY_ONCE":
if os.path.exists('/configured'):
LOG.info("This container has already been configured; "
"Refusing to copy new configs.")
sys.exit(0)
else:
copy_configurations()
f = open('/configured', 'w+')
f.close()
else:
LOG.error("KOLLA_CONFIG_STRATEGY is not set properly: %s."
% kolla_config_strategy)
sys.exit(1)
def main():
execute_config_strategy()
return 0
if __name__ == "__main__":
sys.exit(main())