2014-12-05 14:25:28 -05:00
|
|
|
#!/bin/bash
|
|
|
|
#
|
2015-03-09 15:16:10 -05:00
|
|
|
# **lib/meta-config** - Configuration file manipulation functions
|
|
|
|
#
|
|
|
|
# Support for DevStack's local.conf meta-config sections
|
|
|
|
#
|
2013-09-13 15:05:51 -05:00
|
|
|
# These functions have no external dependencies and the following side-effects:
|
|
|
|
#
|
|
|
|
# CONFIG_AWK_CMD is defined, default is ``awk``
|
|
|
|
|
|
|
|
# Meta-config files contain multiple INI-style configuration files
|
|
|
|
# using a specific new section header to delimit them:
|
|
|
|
#
|
|
|
|
# [[group-name|file-name]]
|
|
|
|
#
|
|
|
|
# group-name refers to the group of configuration file changes to be processed
|
2013-10-22 07:43:22 -04:00
|
|
|
# at a particular time. These are called phases in ``stack.sh`` but
|
2013-09-13 15:05:51 -05:00
|
|
|
# group here as these functions are not DevStack-specific.
|
|
|
|
#
|
|
|
|
# file-name is the destination of the config file
|
|
|
|
|
|
|
|
# Save trace setting
|
2015-10-13 11:03:03 +11:00
|
|
|
_XTRACE_INC_META=$(set +o | grep xtrace)
|
2013-09-13 15:05:51 -05:00
|
|
|
set +o xtrace
|
|
|
|
|
|
|
|
|
|
|
|
# Allow the awk command to be overridden on legacy platforms
|
|
|
|
CONFIG_AWK_CMD=${CONFIG_AWK_CMD:-awk}
|
|
|
|
|
|
|
|
# Get the section for the specific group and config file
|
|
|
|
# get_meta_section infile group configfile
|
2014-02-21 15:35:08 +11:00
|
|
|
function get_meta_section {
|
2013-09-13 15:05:51 -05:00
|
|
|
local file=$1
|
|
|
|
local matchgroup=$2
|
|
|
|
local configfile=$3
|
|
|
|
|
|
|
|
[[ -r $file ]] || return 0
|
|
|
|
[[ -z $configfile ]] && return 0
|
|
|
|
|
|
|
|
$CONFIG_AWK_CMD -v matchgroup=$matchgroup -v configfile=$configfile '
|
|
|
|
BEGIN { group = "" }
|
2013-12-20 11:55:08 +09:00
|
|
|
/^\[\[.+\|.*\]\]/ {
|
2016-11-26 00:43:07 +09:00
|
|
|
gsub("[][]", "", $1);
|
|
|
|
split($1, a, "|");
|
|
|
|
if (a[1] == matchgroup && a[2] == configfile) {
|
|
|
|
group=a[1]
|
2013-09-13 15:05:51 -05:00
|
|
|
} else {
|
|
|
|
group=""
|
|
|
|
}
|
|
|
|
next
|
|
|
|
}
|
|
|
|
{
|
|
|
|
if (group != "")
|
|
|
|
print $0
|
|
|
|
}
|
|
|
|
' $file
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Get a list of config files for a specific group
|
|
|
|
# get_meta_section_files infile group
|
2014-02-21 15:35:08 +11:00
|
|
|
function get_meta_section_files {
|
2013-09-13 15:05:51 -05:00
|
|
|
local file=$1
|
|
|
|
local matchgroup=$2
|
|
|
|
|
|
|
|
[[ -r $file ]] || return 0
|
|
|
|
|
|
|
|
$CONFIG_AWK_CMD -v matchgroup=$matchgroup '
|
2013-10-22 07:43:22 -04:00
|
|
|
/^\[\[.+\|.*\]\]/ {
|
|
|
|
gsub("[][]", "", $1);
|
|
|
|
split($1, a, "|");
|
|
|
|
if (a[1] == matchgroup)
|
|
|
|
print a[2]
|
|
|
|
}
|
2013-09-13 15:05:51 -05:00
|
|
|
' $file
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Merge the contents of a meta-config file into its destination config file
|
|
|
|
# If configfile does not exist it will be created.
|
|
|
|
# merge_config_file infile group configfile
|
2014-02-21 15:35:08 +11:00
|
|
|
function merge_config_file {
|
2013-09-13 15:05:51 -05:00
|
|
|
local file=$1
|
|
|
|
local matchgroup=$2
|
|
|
|
local configfile=$3
|
|
|
|
|
2015-04-17 11:53:40 +10:00
|
|
|
# note, configfile might be a variable (note the iniset, etc
|
|
|
|
# created in the mega-awk below is "eval"ed too, so we just leave
|
|
|
|
# it alone.
|
2015-09-01 10:33:10 +02:00
|
|
|
local real_configfile
|
|
|
|
real_configfile=$(eval echo $configfile)
|
2015-04-17 11:53:40 +10:00
|
|
|
if [ ! -f $real_configfile ]; then
|
2015-09-01 10:33:10 +02:00
|
|
|
touch $real_configfile || die $LINENO "could not create config file $real_configfile ($configfile)"
|
2015-04-17 11:53:40 +10:00
|
|
|
fi
|
|
|
|
|
2013-09-13 15:05:51 -05:00
|
|
|
get_meta_section $file $matchgroup $configfile | \
|
|
|
|
$CONFIG_AWK_CMD -v configfile=$configfile '
|
2014-10-15 21:40:53 -04:00
|
|
|
BEGIN {
|
|
|
|
section = ""
|
|
|
|
last_section = ""
|
|
|
|
section_count = 0
|
|
|
|
}
|
2013-09-13 15:05:51 -05:00
|
|
|
/^\[.+\]/ {
|
|
|
|
gsub("[][]", "", $1);
|
|
|
|
section=$1
|
|
|
|
next
|
|
|
|
}
|
|
|
|
/^ *\#/ {
|
|
|
|
next
|
|
|
|
}
|
2013-12-04 17:20:28 -06:00
|
|
|
/^[^ \t]+/ {
|
local.conf processing doesn't handle '=' in values
When attempting to add a libvirt section with a volume_drivers entry
to $NOVA_CONF, via a post-config block in the local.conf file, I
encountered problems; the value for this attribute takes the form
driver=python.import.path.to.driver
but the value actually populated in the $NOVA_CONF was truncated at the
equals.
Taking the iscsi driver setting specified in the official nova.conf
documentation as an example, if I have the following in my local.conf
file:
[[post-config|$NOVA_CONF]]
[libvirt]
volume_drivers = iscsi=nova.virt.libvirt.volume.LibvirtISCSIVolumeDriver
I will see that the generated $NOVA_CONF has the following:
[libvirt]
volume_driver = iscsi
This occurs because the existing handling for a post-config setion, as
implemented in merge_config_file(), splits the line on the equals sign,
and then uses the first and seconds elements of the resulting array as
attribute name and value respectively.
However when an equals occurs as part of the value this results in the
value being truncated at the first equals in the value.
The fix I've implemented, based upon review feedback, extracts the
contents of $0 before the first equals as the attr name, and extracts
the remainder after the equals as the value. Then it strips the leading
and trailing whitespaces from both as appropriate.
I've also added test5 to tests/test_config.sh to test for, and verify,
correct operation when this scenario is encountered. Similarly I've
added test6 to ensure that trailing spaces in values are stripped
correctly.
Change-Id: Id0cb1e6e1cece21bc5dbf427c4d756af86fbd927
Closes-Bug: #1374482
2014-10-09 16:16:42 -04:00
|
|
|
# get offset of first '=' in $0
|
|
|
|
eq_idx = index($0, "=")
|
|
|
|
# extract attr & value from $0
|
|
|
|
attr = substr($0, 1, eq_idx - 1)
|
|
|
|
value = substr($0, eq_idx + 1)
|
|
|
|
# only need to strip trailing whitespace from attr
|
|
|
|
sub(/[ \t]*$/, "", attr)
|
|
|
|
# need to strip leading & trailing whitespace from value
|
|
|
|
sub(/^[ \t]*/, "", value)
|
|
|
|
sub(/[ \t]*$/, "", value)
|
2014-10-15 21:40:53 -04:00
|
|
|
|
|
|
|
# cfg_attr_count: number of config lines per [section, attr]
|
|
|
|
# cfg_attr: three dimensional array to keep all the config lines per [section, attr]
|
|
|
|
# cfg_section: keep the section names in the same order as they appear in local.conf
|
|
|
|
# cfg_sec_attr_name: keep the attr names in the same order as they appear in local.conf
|
|
|
|
if (! (section, attr) in cfg_attr_count) {
|
|
|
|
if (section != last_section) {
|
|
|
|
cfg_section[section_count++] = section
|
|
|
|
last_section = section
|
|
|
|
}
|
|
|
|
attr_count = cfg_sec_attr_count[section_count - 1]++
|
|
|
|
cfg_sec_attr_name[section_count - 1, attr_count] = attr
|
|
|
|
|
|
|
|
cfg_attr[section, attr, 0] = value
|
|
|
|
cfg_attr_count[section, attr] = 1
|
|
|
|
} else {
|
|
|
|
lno = cfg_attr_count[section, attr]++
|
|
|
|
cfg_attr[section, attr, lno] = value
|
|
|
|
}
|
|
|
|
}
|
|
|
|
END {
|
|
|
|
# Process each section in order
|
|
|
|
for (sno = 0; sno < section_count; sno++) {
|
|
|
|
section = cfg_section[sno]
|
|
|
|
# The ini routines simply append a config item immediately
|
|
|
|
# after the section header. To keep the same order as defined
|
|
|
|
# in local.conf, invoke the ini routines in the reverse order
|
|
|
|
for (attr_no = cfg_sec_attr_count[sno] - 1; attr_no >=0; attr_no--) {
|
|
|
|
attr = cfg_sec_attr_name[sno, attr_no]
|
|
|
|
if (cfg_attr_count[section, attr] == 1)
|
2014-10-29 21:53:56 +11:00
|
|
|
print "iniset " configfile " " section " " attr " \"" cfg_attr[section, attr, 0] "\""
|
2014-10-15 21:40:53 -04:00
|
|
|
else {
|
|
|
|
# For multiline, invoke the ini routines in the reverse order
|
|
|
|
count = cfg_attr_count[section, attr]
|
2014-12-13 11:56:16 -07:00
|
|
|
print "inidelete " configfile " " section " " attr
|
2014-10-29 21:53:56 +11:00
|
|
|
print "iniset " configfile " " section " " attr " \"" cfg_attr[section, attr, count - 1] "\""
|
2014-10-15 21:40:53 -04:00
|
|
|
for (l = count -2; l >= 0; l--)
|
2014-10-29 21:53:56 +11:00
|
|
|
print "iniadd_literal " configfile " " section " " attr " \"" cfg_attr[section, attr, l] "\""
|
2014-10-15 21:40:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-09-13 15:05:51 -05:00
|
|
|
}
|
|
|
|
' | while read a; do eval "$a"; done
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Merge all of the files specified by group
|
|
|
|
# merge_config_group infile group [group ...]
|
2014-02-21 15:35:08 +11:00
|
|
|
function merge_config_group {
|
2013-09-13 15:05:51 -05:00
|
|
|
local localfile=$1; shift
|
|
|
|
local matchgroups=$@
|
|
|
|
|
|
|
|
[[ -r $localfile ]] || return 0
|
|
|
|
|
2014-07-25 14:57:54 -05:00
|
|
|
local configfile group
|
2013-09-13 15:05:51 -05:00
|
|
|
for group in $matchgroups; do
|
|
|
|
for configfile in $(get_meta_section_files $localfile $group); do
|
2015-09-01 10:33:10 +02:00
|
|
|
local realconfigfile
|
|
|
|
local dir
|
|
|
|
|
|
|
|
realconfigfile=$(eval "echo $configfile")
|
|
|
|
if [[ -z $realconfigfile ]]; then
|
2016-12-09 07:33:01 -05:00
|
|
|
warn $LINENO "unknown config file specification: $configfile is undefined"
|
|
|
|
break
|
2015-09-01 10:33:10 +02:00
|
|
|
fi
|
|
|
|
dir=$(dirname $realconfigfile)
|
|
|
|
if [[ -d $dir ]]; then
|
2013-09-13 15:05:51 -05:00
|
|
|
merge_config_file $localfile $group $configfile
|
2015-09-01 10:33:10 +02:00
|
|
|
else
|
|
|
|
die $LINENO "bogus config file specification $configfile ($configfile=$realconfigfile, $dir is not a directory)"
|
2013-09-13 15:05:51 -05:00
|
|
|
fi
|
|
|
|
done
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
2015-12-23 02:17:01 +00:00
|
|
|
function extract_localrc_section {
|
|
|
|
local configfile=$1 # top_dir/local.conf
|
|
|
|
local localrcfile=$2 # top_dir/localrc
|
|
|
|
local localautofile=$3 # top_dir/.localrc.auto
|
|
|
|
|
|
|
|
if [[ -r $configfile ]]; then
|
|
|
|
LRC=$(get_meta_section_files $configfile local)
|
|
|
|
for lfile in $LRC; do
|
|
|
|
if [[ "$lfile" == "localrc" ]]; then
|
|
|
|
if [[ -r $localrcfile ]]; then
|
|
|
|
echo "localrc and local.conf:[[local]] both exist, using localrc"
|
|
|
|
else
|
|
|
|
echo "# Generated file, do not edit" >$localautofile
|
|
|
|
get_meta_section $configfile local $lfile >>$localautofile
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
fi
|
|
|
|
}
|
2013-09-13 15:05:51 -05:00
|
|
|
|
|
|
|
# Restore xtrace
|
2015-10-13 11:03:03 +11:00
|
|
|
$_XTRACE_INC_META
|
2013-09-13 15:05:51 -05:00
|
|
|
|
|
|
|
# Local variables:
|
|
|
|
# mode: shell-script
|
|
|
|
# End:
|