blob: e5f902d1dd00a2478f14516b3df251c78cbb7f47 [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
Dean Troyerbf2ad702015-03-09 15:16:10 -050023INC_META_XTRACE=$(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 /^\[\[.+\|.*\]\]/ {
Dean Troyer893e6632013-09-13 15:05:51 -050043 if (group == "") {
44 gsub("[][]", "", $1);
45 split($1, a, "|");
46 if (a[1] == matchgroup && a[2] == configfile) {
47 group=a[1]
48 }
49 } else {
50 group=""
51 }
52 next
53 }
54 {
55 if (group != "")
56 print $0
57 }
58 ' $file
59}
60
61
62# Get a list of config files for a specific group
63# get_meta_section_files infile group
Ian Wienandaee18c72014-02-21 15:35:08 +110064function get_meta_section_files {
Dean Troyer893e6632013-09-13 15:05:51 -050065 local file=$1
66 local matchgroup=$2
67
68 [[ -r $file ]] || return 0
69
70 $CONFIG_AWK_CMD -v matchgroup=$matchgroup '
Sean Dague537d4022013-10-22 07:43:22 -040071 /^\[\[.+\|.*\]\]/ {
72 gsub("[][]", "", $1);
73 split($1, a, "|");
74 if (a[1] == matchgroup)
75 print a[2]
76 }
Dean Troyer893e6632013-09-13 15:05:51 -050077 ' $file
78}
79
80
81# Merge the contents of a meta-config file into its destination config file
82# If configfile does not exist it will be created.
83# merge_config_file infile group configfile
Ian Wienandaee18c72014-02-21 15:35:08 +110084function merge_config_file {
Dean Troyer893e6632013-09-13 15:05:51 -050085 local file=$1
86 local matchgroup=$2
87 local configfile=$3
88
Ian Wienandfa3e8412015-04-17 11:53:40 +100089 # note, configfile might be a variable (note the iniset, etc
90 # created in the mega-awk below is "eval"ed too, so we just leave
91 # it alone.
92 local real_configfile=$(eval echo $configfile)
93 if [ ! -f $real_configfile ]; then
94 touch $real_configfile
95 fi
96
Dean Troyer893e6632013-09-13 15:05:51 -050097 get_meta_section $file $matchgroup $configfile | \
98 $CONFIG_AWK_CMD -v configfile=$configfile '
Robert Li751ad1a2014-10-15 21:40:53 -040099 BEGIN {
100 section = ""
101 last_section = ""
102 section_count = 0
103 }
Dean Troyer893e6632013-09-13 15:05:51 -0500104 /^\[.+\]/ {
105 gsub("[][]", "", $1);
106 section=$1
107 next
108 }
109 /^ *\#/ {
110 next
111 }
Dean Troyer2ac8b3f2013-12-04 17:20:28 -0600112 /^[^ \t]+/ {
Fergal Mc Carthycc87c282014-10-09 16:16:42 -0400113 # get offset of first '=' in $0
114 eq_idx = index($0, "=")
115 # extract attr & value from $0
116 attr = substr($0, 1, eq_idx - 1)
117 value = substr($0, eq_idx + 1)
118 # only need to strip trailing whitespace from attr
119 sub(/[ \t]*$/, "", attr)
120 # need to strip leading & trailing whitespace from value
121 sub(/^[ \t]*/, "", value)
122 sub(/[ \t]*$/, "", value)
Robert Li751ad1a2014-10-15 21:40:53 -0400123
124 # cfg_attr_count: number of config lines per [section, attr]
125 # cfg_attr: three dimensional array to keep all the config lines per [section, attr]
126 # cfg_section: keep the section names in the same order as they appear in local.conf
127 # cfg_sec_attr_name: keep the attr names in the same order as they appear in local.conf
128 if (! (section, attr) in cfg_attr_count) {
129 if (section != last_section) {
130 cfg_section[section_count++] = section
131 last_section = section
132 }
133 attr_count = cfg_sec_attr_count[section_count - 1]++
134 cfg_sec_attr_name[section_count - 1, attr_count] = attr
135
136 cfg_attr[section, attr, 0] = value
137 cfg_attr_count[section, attr] = 1
138 } else {
139 lno = cfg_attr_count[section, attr]++
140 cfg_attr[section, attr, lno] = value
141 }
142 }
143 END {
144 # Process each section in order
145 for (sno = 0; sno < section_count; sno++) {
146 section = cfg_section[sno]
147 # The ini routines simply append a config item immediately
148 # after the section header. To keep the same order as defined
149 # in local.conf, invoke the ini routines in the reverse order
150 for (attr_no = cfg_sec_attr_count[sno] - 1; attr_no >=0; attr_no--) {
151 attr = cfg_sec_attr_name[sno, attr_no]
152 if (cfg_attr_count[section, attr] == 1)
Ian Wienandf3bf8b62014-10-29 21:53:56 +1100153 print "iniset " configfile " " section " " attr " \"" cfg_attr[section, attr, 0] "\""
Robert Li751ad1a2014-10-15 21:40:53 -0400154 else {
155 # For multiline, invoke the ini routines in the reverse order
156 count = cfg_attr_count[section, attr]
Doug Wiegley1f65fd62014-12-13 11:56:16 -0700157 print "inidelete " configfile " " section " " attr
Ian Wienandf3bf8b62014-10-29 21:53:56 +1100158 print "iniset " configfile " " section " " attr " \"" cfg_attr[section, attr, count - 1] "\""
Robert Li751ad1a2014-10-15 21:40:53 -0400159 for (l = count -2; l >= 0; l--)
Ian Wienandf3bf8b62014-10-29 21:53:56 +1100160 print "iniadd_literal " configfile " " section " " attr " \"" cfg_attr[section, attr, l] "\""
Robert Li751ad1a2014-10-15 21:40:53 -0400161 }
162 }
163 }
Dean Troyer893e6632013-09-13 15:05:51 -0500164 }
165 ' | while read a; do eval "$a"; done
Dean Troyer893e6632013-09-13 15:05:51 -0500166}
167
168
169# Merge all of the files specified by group
170# merge_config_group infile group [group ...]
Ian Wienandaee18c72014-02-21 15:35:08 +1100171function merge_config_group {
Dean Troyer893e6632013-09-13 15:05:51 -0500172 local localfile=$1; shift
173 local matchgroups=$@
174
175 [[ -r $localfile ]] || return 0
176
Dean Troyerb1e3d0f2014-07-25 14:57:54 -0500177 local configfile group
Dean Troyer893e6632013-09-13 15:05:51 -0500178 for group in $matchgroups; do
179 for configfile in $(get_meta_section_files $localfile $group); do
Ryota MIBU410f5c02014-04-04 02:00:31 +0900180 if [[ -d $(dirname $(eval "echo $configfile")) ]]; then
Dean Troyer893e6632013-09-13 15:05:51 -0500181 merge_config_file $localfile $group $configfile
182 fi
183 done
184 done
185}
186
187
188# Restore xtrace
Dean Troyerbf2ad702015-03-09 15:16:10 -0500189$INC_META_XTRACE
Dean Troyer893e6632013-09-13 15:05:51 -0500190
191# Local variables:
192# mode: shell-script
193# End: