
Containers use configuration files from the path /var/lib/config-data/puppet-generated/<service/ and not from /var/lib/config-data/<service>/ Change-Id: I1e5c4935b72fcabd5256d0bf8014cae3beb314a4
155 lines
5.4 KiB
Python
155 lines
5.4 KiB
Python
#!/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 sys
|
|
import os
|
|
import subprocess
|
|
# usage: openstack-config-parser.py [service] [output file]
|
|
|
|
def run_cmd(cmd):
|
|
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE)
|
|
stdout, stderr = process.communicate()
|
|
output_dict = {}
|
|
output_dict['stdout'] = stdout.strip()
|
|
output_dict['stderr'] = stderr.strip()
|
|
output_dict['rc'] = process.returncode
|
|
return output_dict
|
|
|
|
def strip_chars(line):
|
|
forbidden_chars = ['#', '\n', '"', '\\', ' ', '<', '>']
|
|
for char in forbidden_chars:
|
|
line = line.replace(char, '')
|
|
return line
|
|
|
|
def parse_config(serviceName, fileName):
|
|
# a dict containing key/value pairs, last value is what is stored.
|
|
values = {}
|
|
with open(fileName) as config:
|
|
section = None
|
|
for line in config:
|
|
pair = strip_chars(line)
|
|
pair = pair.split('=')
|
|
# excludes any line without a key/val pair
|
|
valid_line = not line.startswith("# ") and \
|
|
'[' not in line and line != '\n' \
|
|
and line != '#\n' and "password" \
|
|
not in line.lower()
|
|
if line.startswith('['):
|
|
section = line.replace('[','').replace(']','').replace('\n','')
|
|
if '#' not in line and valid_line and not section == None and len(pair) == 2:
|
|
pair[0] = strip_chars(pair[0])
|
|
pair[1] = strip_chars(pair[1])
|
|
values["openstack_S_" + serviceName + "_S_" + section + "_S_" + pair[0]] = pair[1]
|
|
return values
|
|
|
|
|
|
def try_type(val):
|
|
try:
|
|
int(val)
|
|
return val
|
|
except (ValueError, TypeError):
|
|
try:
|
|
float(val)
|
|
return val
|
|
except (ValueError, TypeError):
|
|
if type(val) is list:
|
|
return "\"" + str(val) + "\""
|
|
elif val.lower() in ("true", "false"):
|
|
return val
|
|
else:
|
|
return "\"" + val + "\""
|
|
|
|
|
|
def add_conf_location(serviceName, fileName, values):
|
|
# Stores the exact location we gathered this config from.
|
|
index = "openstack_S_" + serviceName + "_S_" + "Browbeat" + "_S_" + "gather_conf_path"
|
|
if index in values:
|
|
values[index].append(fileName)
|
|
else:
|
|
values[index] = [fileName]
|
|
|
|
def print_vars_file(values, fileName):
|
|
with open(fileName, 'w') as output:
|
|
for key in values:
|
|
output.write(key + ": " + try_type(values[key]) + "\n")
|
|
|
|
def is_containerized(service_name):
|
|
out = run_cmd("docker ps")
|
|
if service_name in out['stdout']:
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def get_configs_list(path, extension='.conf'):
|
|
configs = []
|
|
for item in os.listdir(path):
|
|
if item.endswith(extension):
|
|
configs.extend([item])
|
|
return configs
|
|
|
|
def get_neutron_plugin(output, cfg_path):
|
|
plugin = output['openstack_S_neutron_S_DEFAULT_S_core_plugin']
|
|
plugin_path = "{}/plugins/{}/".format(cfg_path, plugin)
|
|
for item in get_configs_list(plugin_path, extension='.ini'):
|
|
full_path = "{}/{}".format(plugin_path,
|
|
item)
|
|
output.update(parse_config("neutron-plugin", full_path))
|
|
add_conf_location("neutron", full_path, output)
|
|
return output
|
|
|
|
def main():
|
|
if len(sys.argv) < 3:
|
|
print("usage: openstack-config-parser.py [service] [output file]")
|
|
exit(1)
|
|
|
|
service_name = sys.argv[1]
|
|
outfile = sys.argv[2]
|
|
|
|
# This is a list of services that require exceptions from the usual
|
|
# pattern when gathering their config files
|
|
pattern_exceptions = ['glance']
|
|
in_container = is_containerized(service_name)
|
|
|
|
|
|
if 'undercloud' in service_name:
|
|
cfg_path = "/home/stack"
|
|
elif in_container and service_name not in pattern_exceptions:
|
|
cfg_path = "/var/lib/config-data/puppet-generated/{}/etc/{}".format(
|
|
service_name, service_name)
|
|
# Glance has all configs in a folder named glance_api, ps shows no
|
|
# processes outside of the container, so I assume those are the right
|
|
# configs, even though the container is also named glance-api
|
|
# jkilpatr 7/13/17
|
|
elif in_container and 'glance' in service_name:
|
|
cfg_path = "/var/lib/config-data/glance_api/etc/glance"
|
|
else:
|
|
cfg_path = "/etc/{}".format(service_name)
|
|
|
|
print("Parsing all .conf files in {}".format(cfg_path))
|
|
output = {}
|
|
for item in get_configs_list(cfg_path):
|
|
full_path = "{}/{}".format(cfg_path,
|
|
item)
|
|
output.update(parse_config(service_name, full_path))
|
|
add_conf_location(service_name, full_path, output)
|
|
# Required to find and load the active neutron plugin file.
|
|
if 'neutron' in service_name:
|
|
output.update(get_neutron_plugin(output, cfg_path))
|
|
|
|
print_vars_file(output, outfile)
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main())
|
|
|