blob: 6252135747e9a54a1d068fca600dd01c6dd5c33f [file] [log] [blame]
Sean Daguee263c822014-12-05 14:25:28 -05001#!/bin/bash
2#
Dean Troyerbf2ad702015-03-09 15:16:10 -05003# **lib/meta-config** - Configuration file manipulation functions
4#
5# Support for DevStack's local.conf meta-config sections
6#
Dean Troyer893e6632013-09-13 15:05:51 -05007# These functions have no external dependencies and the following side-effects:
8#
9# CONFIG_AWK_CMD is defined, default is ``awk``
10
11# Meta-config files contain multiple INI-style configuration files
12# using a specific new section header to delimit them:
13#
14# [[group-name|file-name]]
15#
16# group-name refers to the group of configuration file changes to be processed
Sean Dague537d4022013-10-22 07:43:22 -040017# at a particular time. These are called phases in ``stack.sh`` but
Dean Troyer893e6632013-09-13 15:05:51 -050018# group here as these functions are not DevStack-specific.
19#
20# file-name is the destination of the config file
21
22# Save trace setting
Ian Wienand523f4882015-10-13 11:03:03 +110023_XTRACE_INC_META=$(set +o | grep xtrace)
Dean Troyer893e6632013-09-13 15:05:51 -050024set +o xtrace
25
26
27# Allow the awk command to be overridden on legacy platforms
28CONFIG_AWK_CMD=${CONFIG_AWK_CMD:-awk}
29
30# Get the section for the specific group and config file
31# get_meta_section infile group configfile
Ian Wienandaee18c72014-02-21 15:35:08 +110032function get_meta_section {
Dean Troyer893e6632013-09-13 15:05:51 -050033 local file=$1
34 local matchgroup=$2
35 local configfile=$3
36
37 [[ -r $file ]] || return 0
38 [[ -z $configfile ]] && return 0
39
40 $CONFIG_AWK_CMD -v matchgroup=$matchgroup -v configfile=$configfile '
41 BEGIN { group = "" }
Isaku Yamahatabff00142013-12-20 11:55:08 +090042 /^\[\[.+\|.*\]\]/ {
YAMAMOTO Takashi02f3f9a2016-11-26 00:43:07 +090043 gsub("[][]", "", $1);
44 split($1, a, "|");
45 if (a[1] == matchgroup && a[2] == configfile) {
46 group=a[1]
Dean Troyer893e6632013-09-13 15:05:51 -050047 } else {
48 group=""
49 }
50 next
51 }
52 {
53 if (group != "")
54 print $0
55 }
56 ' $file
57}
58
59
60# Get a list of config files for a specific group
61# get_meta_section_files infile group
Ian Wienandaee18c72014-02-21 15:35:08 +110062function get_meta_section_files {
Dean Troyer893e6632013-09-13 15:05:51 -050063 local file=$1
64 local matchgroup=$2
65
66 [[ -r $file ]] || return 0
67
68 $CONFIG_AWK_CMD -v matchgroup=$matchgroup '
Sean Dague537d4022013-10-22 07:43:22 -040069 /^\[\[.+\|.*\]\]/ {
70 gsub("[][]", "", $1);
71 split($1, a, "|");
72 if (a[1] == matchgroup)
73 print a[2]
74 }
Dean Troyer893e6632013-09-13 15:05:51 -050075 ' $file
76}
77
78
79# Merge the contents of a meta-config file into its destination config file
80# If configfile does not exist it will be created.
81# merge_config_file infile group configfile
Ian Wienandaee18c72014-02-21 15:35:08 +110082function merge_config_file {
Dean Troyer893e6632013-09-13 15:05:51 -050083 local file=$1
84 local matchgroup=$2
85 local configfile=$3
86
Ian Wienandfa3e8412015-04-17 11:53:40 +100087 # note, configfile might be a variable (note the iniset, etc
88 # created in the mega-awk below is "eval"ed too, so we just leave
89 # it alone.
Thomas Morin85f42f62015-09-01 10:33:10 +020090 local real_configfile
91 real_configfile=$(eval echo $configfile)
Ian Wienandfa3e8412015-04-17 11:53:40 +100092 if [ ! -f $real_configfile ]; then
Thomas Morin85f42f62015-09-01 10:33:10 +020093 touch $real_configfile || die $LINENO "could not create config file $real_configfile ($configfile)"
Ian Wienandfa3e8412015-04-17 11:53:40 +100094 fi
95
Dean Troyer893e6632013-09-13 15:05:51 -050096 get_meta_section $file $matchgroup $configfile | \
97 $CONFIG_AWK_CMD -v configfile=$configfile '
Robert Li751ad1a2014-10-15 21:40:53 -040098 BEGIN {
99 section = ""
100 last_section = ""
101 section_count = 0
102 }
Dean Troyer893e6632013-09-13 15:05:51 -0500103 /^\[.+\]/ {
104 gsub("[][]", "", $1);
105 section=$1
106 next
107 }
108 /^ *\#/ {
109 next
110 }
Dean Troyer2ac8b3f2013-12-04 17:20:28 -0600111 /^[^ \t]+/ {
Fergal Mc Carthycc87c282014-10-09 16:16:42 -0400112 # get offset of first '=' in $0
113 eq_idx = index($0, "=")
114 # extract attr & value from $0
115 attr = substr($0, 1, eq_idx - 1)
116 value = substr($0, eq_idx + 1)
117 # only need to strip trailing whitespace from attr
118 sub(/[ \t]*$/, "", attr)
119 # need to strip leading & trailing whitespace from value
120 sub(/^[ \t]*/, "", value)
121 sub(/[ \t]*$/, "", value)
Robert Li751ad1a2014-10-15 21:40:53 -0400122
123 # cfg_attr_count: number of config lines per [section, attr]
124 # cfg_attr: three dimensional array to keep all the config lines per [section, attr]
125 # cfg_section: keep the section names in the same order as they appear in local.conf
126 # cfg_sec_attr_name: keep the attr names in the same order as they appear in local.conf
127 if (! (section, attr) in cfg_attr_count) {
128 if (section != last_section) {
129 cfg_section[section_count++] = section
130 last_section = section
131 }
132 attr_count = cfg_sec_attr_count[section_count - 1]++
133 cfg_sec_attr_name[section_count - 1, attr_count] = attr
134
135 cfg_attr[section, attr, 0] = value
136 cfg_attr_count[section, attr] = 1
137 } else {
138 lno = cfg_attr_count[section, attr]++
139 cfg_attr[section, attr, lno] = value
140 }
141 }
142 END {
143 # Process each section in order
144 for (sno = 0; sno < section_count; sno++) {
145 section = cfg_section[sno]
146 # The ini routines simply append a config item immediately
147 # after the section header. To keep the same order as defined
148 # in local.conf, invoke the ini routines in the reverse order
149 for (attr_no = cfg_sec_attr_count[sno] - 1; attr_no >=0; attr_no--) {
150 attr = cfg_sec_attr_name[sno, attr_no]
151 if (cfg_attr_count[section, attr] == 1)
Ian Wienandf3bf8b62014-10-29 21:53:56 +1100152 print "iniset " configfile " " section " " attr " \"" cfg_attr[section, attr, 0] "\""
Robert Li751ad1a2014-10-15 21:40:53 -0400153 else {
154 # For multiline, invoke the ini routines in the reverse order
155 count = cfg_attr_count[section, attr]
Doug Wiegley1f65fd62014-12-13 11:56:16 -0700156 print "inidelete " configfile " " section " " attr
Ian Wienandf3bf8b62014-10-29 21:53:56 +1100157 print "iniset " configfile " " section " " attr " \"" cfg_attr[section, attr, count - 1] "\""
Robert Li751ad1a2014-10-15 21:40:53 -0400158 for (l = count -2; l >= 0; l--)
Ian Wienandf3bf8b62014-10-29 21:53:56 +1100159 print "iniadd_literal " configfile " " section " " attr " \"" cfg_attr[section, attr, l] "\""
Robert Li751ad1a2014-10-15 21:40:53 -0400160 }
161 }
162 }
Dean Troyer893e6632013-09-13 15:05:51 -0500163 }
164 ' | while read a; do eval "$a"; done
Dean Troyer893e6632013-09-13 15:05:51 -0500165}
166
167
168# Merge all of the files specified by group
169# merge_config_group infile group [group ...]
Ian Wienandaee18c72014-02-21 15:35:08 +1100170function merge_config_group {
Dean Troyer893e6632013-09-13 15:05:51 -0500171 local localfile=$1; shift
172 local matchgroups=$@
173
174 [[ -r $localfile ]] || return 0
175
Dean Troyerb1e3d0f2014-07-25 14:57:54 -0500176 local configfile group
Dean Troyer893e6632013-09-13 15:05:51 -0500177 for group in $matchgroups; do
178 for configfile in $(get_meta_section_files $localfile $group); do
Thomas Morin85f42f62015-09-01 10:33:10 +0200179 local realconfigfile
180 local dir
181
182 realconfigfile=$(eval "echo $configfile")
183 if [[ -z $realconfigfile ]]; then
184 die $LINENO "bogus config file specification: $configfile is undefined"
185 fi
186 dir=$(dirname $realconfigfile)
187 if [[ -d $dir ]]; then
Dean Troyer893e6632013-09-13 15:05:51 -0500188 merge_config_file $localfile $group $configfile
Thomas Morin85f42f62015-09-01 10:33:10 +0200189 else
190 die $LINENO "bogus config file specification $configfile ($configfile=$realconfigfile, $dir is not a directory)"
Dean Troyer893e6632013-09-13 15:05:51 -0500191 fi
192 done
193 done
194}
195
Huan Xiecc6af3f2015-12-23 02:17:01 +0000196function extract_localrc_section {
197 local configfile=$1 # top_dir/local.conf
198 local localrcfile=$2 # top_dir/localrc
199 local localautofile=$3 # top_dir/.localrc.auto
200
201 if [[ -r $configfile ]]; then
202 LRC=$(get_meta_section_files $configfile local)
203 for lfile in $LRC; do
204 if [[ "$lfile" == "localrc" ]]; then
205 if [[ -r $localrcfile ]]; then
206 echo "localrc and local.conf:[[local]] both exist, using localrc"
207 else
208 echo "# Generated file, do not edit" >$localautofile
209 get_meta_section $configfile local $lfile >>$localautofile
210 fi
211 fi
212 done
213 fi
214}
Dean Troyer893e6632013-09-13 15:05:51 -0500215
216# Restore xtrace
Ian Wienand523f4882015-10-13 11:03:03 +1100217$_XTRACE_INC_META
Dean Troyer893e6632013-09-13 15:05:51 -0500218
219# Local variables:
220# mode: shell-script
221# End: