inc/meta-config
e263c82e
 #!/bin/bash
 #
bf2ad701
 # **lib/meta-config** - Configuration file manipulation functions
 #
 # Support for DevStack's local.conf meta-config sections
 #
893e6636
 # 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
537d4025
 # at a particular time.  These are called phases in ``stack.sh`` but
893e6636
 # group here as these functions are not DevStack-specific.
 #
 # file-name is the destination of the config file
 
 # Save trace setting
523f4880
 _XTRACE_INC_META=$(set +o | grep xtrace)
893e6636
 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
aee18c74
 function get_meta_section {
893e6636
     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 = "" }
bff00145
         /^\[\[.+\|.*\]\]/ {
02f3f9a6
             gsub("[][]", "", $1);
             split($1, a, "|");
             if (a[1] == matchgroup && a[2] == configfile) {
                 group=a[1]
893e6636
             } else {
                 group=""
             }
             next
         }
         {
             if (group != "")
                 print $0
         }
     ' $file
 }
 
 
 # Get a list of config files for a specific group
 # get_meta_section_files infile group
aee18c74
 function get_meta_section_files {
893e6636
     local file=$1
     local matchgroup=$2
 
     [[ -r $file ]] || return 0
 
     $CONFIG_AWK_CMD -v matchgroup=$matchgroup '
537d4025
         /^\[\[.+\|.*\]\]/ {
             gsub("[][]", "", $1);
             split($1, a, "|");
             if (a[1] == matchgroup)
                 print a[2]
         }
893e6636
     ' $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
aee18c74
 function merge_config_file {
893e6636
     local file=$1
     local matchgroup=$2
     local configfile=$3
 
fa3e8412
     # 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.
85f42f69
     local real_configfile
     real_configfile=$(eval echo $configfile)
fa3e8412
     if [ ! -f $real_configfile ]; then
85f42f69
         touch $real_configfile || die $LINENO "could not create config file $real_configfile ($configfile)"
fa3e8412
     fi
 
893e6636
     get_meta_section $file $matchgroup $configfile | \
     $CONFIG_AWK_CMD -v configfile=$configfile '
751ad1aa
         BEGIN {
             section = ""
             last_section = ""
             section_count = 0
         }
893e6636
         /^\[.+\]/ {
             gsub("[][]", "", $1);
             section=$1
             next
         }
         /^ *\#/ {
             next
         }
2ac8b3f3
         /^[^ \t]+/ {
cc87c287
             # 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)
751ad1aa
 
             # 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)
f3bf8b6c
                         print "iniset " configfile " " section " " attr " \"" cfg_attr[section, attr, 0] "\""
751ad1aa
                     else {
                         # For multiline, invoke the ini routines in the reverse order
                         count = cfg_attr_count[section, attr]
1f65fd64
                         print "inidelete " configfile " " section " " attr
f3bf8b6c
                         print "iniset " configfile " " section " " attr " \"" cfg_attr[section, attr, count - 1] "\""
751ad1aa
                         for (l = count -2; l >= 0; l--)
f3bf8b6c
                             print "iniadd_literal " configfile " " section " " attr " \"" cfg_attr[section, attr, l] "\""
751ad1aa
                     }
                 }
             }
893e6636
         }
     ' | while read a; do eval "$a"; done
 }
 
 
 # Merge all of the files specified by group
 # merge_config_group infile group [group ...]
aee18c74
 function merge_config_group {
893e6636
     local localfile=$1; shift
     local matchgroups=$@
 
     [[ -r $localfile ]] || return 0
 
b1e3d0f2
     local configfile group
893e6636
     for group in $matchgroups; do
         for configfile in $(get_meta_section_files $localfile $group); do
85f42f69
             local realconfigfile
             local dir
 
             realconfigfile=$(eval "echo $configfile")
             if [[ -z $realconfigfile ]]; then
22b63666
                 warn $LINENO "unknown config file specification: $configfile is undefined"
                 break
85f42f69
             fi
             dir=$(dirname $realconfigfile)
             if [[ -d $dir ]]; then
893e6636
                 merge_config_file $localfile $group $configfile
85f42f69
             else
                 die $LINENO "bogus config file specification $configfile ($configfile=$realconfigfile, $dir is not a directory)"
893e6636
             fi
         done
     done
 }
 
cc6af3fc
 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
 }
893e6636
 
 # Restore xtrace
523f4880
 $_XTRACE_INC_META
893e6636
 
 # Local variables:
 # mode: shell-script
 # End: