Browse code

Merge "Add meta-config via local.conf"

Jenkins authored on 2013/10/15 02:49:26
Showing 6 changed files
... ...
@@ -250,3 +250,42 @@ To setup a cells environment add the following to your `localrc`:
250 250
     enable_service n-cell
251 251
 
252 252
 Be aware that there are some features currently missing in cells, one notable one being security groups.  The exercises have been patched to disable functionality not supported by cells.
253
+
254
+
255
+# Local Configuration
256
+
257
+Historically DevStack has used ``localrc`` to contain all local configuration and customizations. More and more of the configuration variables available for DevStack are passed-through to the individual project configuration files.  The old mechanism for this required specific code for each file and did not scale well.  This is handled now by a master local configuration file.
258
+
259
+# local.conf
260
+
261
+The new config file ``local.conf`` is an extended-INI format that introduces a new meta-section header that provides some additional information such as a phase name and destination config filename:
262
+
263
+  [[ <phase> | <filename> ]]
264
+
265
+where <phase> is one of a set of phase names defined by ``stack.sh`` and <filename> is the project config filename.  The filename is eval'ed in the stack.sh context so all environment variables are available and may be used.  Using the project config file variables in the header is strongly suggested (see example of NOVA_CONF below).  If the path of the config file does not exist it is skipped.
266
+
267
+The defined phases are:
268
+
269
+* local - extracts ``localrc`` from ``local.conf`` before ``stackrc`` is sourced
270
+* post-config - runs after the layer 2 services are configured and before they are started
271
+* extra - runs after services are started and before any files in ``extra.d`` are executes
272
+
273
+The file is processed strictly in sequence; meta-sections may be specified more than once but if any settings are duplicated the last to appear in the file will be used.
274
+
275
+  [[post-config|$NOVA_CONF]]
276
+  [DEFAULT]
277
+  use_syslog = True
278
+
279
+  [osapi_v3]
280
+  enabled = False
281
+
282
+A specific meta-section ``local:localrc`` is used to provide a default localrc file.  This allows all custom settings for DevStack to be contained in a single file.  ``localrc`` is not overwritten if it exists to preserve compatability.
283
+
284
+  [[local|localrc]]
285
+  FIXED_RANGE=10.254.1.0/24
286
+  ADMIN_PASSWORD=speciale
287
+  LOGFILE=$DEST/logs/stack.sh.log
288
+
289
+Note that ``Q_PLUGIN_CONF_FILE`` is unique in that it is assumed to _NOT_ start with a ``/`` (slash) character.  A slash will need to be added:
290
+
291
+  [[post-config|/$Q_PLUGIN_CONF_FILE]]
... ...
@@ -155,6 +155,22 @@ function err_if_not_set() {
155 155
 }
156 156
 
157 157
 
158
+# Prints line number and "message" in warning format
159
+# warn $LINENO "message"
160
+function warn() {
161
+    local exitcode=$?
162
+    errXTRACE=$(set +o | grep xtrace)
163
+    set +o xtrace
164
+    local msg="[WARNING] ${BASH_SOURCE[2]}:$1 $2"
165
+    echo $msg 1>&2;
166
+    if [[ -n ${SCREEN_LOGDIR} ]]; then
167
+        echo $msg >> "${SCREEN_LOGDIR}/error.log"
168
+    fi
169
+    $errXTRACE
170
+    return $exitcode
171
+}
172
+
173
+
158 174
 # HTTP and HTTPS proxy servers are supported via the usual environment variables [1]
159 175
 # ``http_proxy``, ``https_proxy`` and ``no_proxy``. They can be set in
160 176
 # ``localrc`` or on the command line if necessary::
161 177
new file mode 100644
... ...
@@ -0,0 +1,130 @@
0
+# lib/config - Configuration file manipulation functions
1
+
2
+# These functions have no external dependencies and the following side-effects:
3
+#
4
+# CONFIG_AWK_CMD is defined, default is ``awk``
5
+
6
+# Meta-config files contain multiple INI-style configuration files
7
+# using a specific new section header to delimit them:
8
+#
9
+#   [[group-name|file-name]]
10
+#
11
+# group-name refers to the group of configuration file changes to be processed
12
+# at a particular time.  These are called phases in ``stack.sh`` but 
13
+# group here as these functions are not DevStack-specific.
14
+#
15
+# file-name is the destination of the config file
16
+
17
+# Save trace setting
18
+C_XTRACE=$(set +o | grep xtrace)
19
+set +o xtrace
20
+
21
+
22
+# Allow the awk command to be overridden on legacy platforms
23
+CONFIG_AWK_CMD=${CONFIG_AWK_CMD:-awk}
24
+
25
+# Get the section for the specific group and config file
26
+# get_meta_section infile group configfile
27
+function get_meta_section() {
28
+    local file=$1
29
+    local matchgroup=$2
30
+    local configfile=$3
31
+
32
+    [[ -r $file ]] || return 0
33
+    [[ -z $configfile ]] && return 0
34
+
35
+    $CONFIG_AWK_CMD -v matchgroup=$matchgroup -v configfile=$configfile '
36
+        BEGIN { group = "" }
37
+        /^\[\[.+|.*\]\]/ {
38
+            if (group == "") {
39
+                gsub("[][]", "", $1);
40
+                split($1, a, "|");
41
+                if (a[1] == matchgroup && a[2] == configfile) {
42
+                    group=a[1]
43
+                }
44
+            } else {
45
+                group=""
46
+            }
47
+            next
48
+        }
49
+        {
50
+            if (group != "")
51
+                print $0
52
+        }
53
+    ' $file
54
+}
55
+
56
+
57
+# Get a list of config files for a specific group
58
+# get_meta_section_files infile group
59
+function get_meta_section_files() {
60
+    local file=$1
61
+    local matchgroup=$2
62
+
63
+    [[ -r $file ]] || return 0
64
+
65
+    $CONFIG_AWK_CMD -v matchgroup=$matchgroup '
66
+      /^\[\[.+\|.*\]\]/ {
67
+          gsub("[][]", "", $1);
68
+          split($1, a, "|");
69
+          if (a[1] == matchgroup)
70
+              print a[2]
71
+      }
72
+    ' $file
73
+}
74
+
75
+
76
+# Merge the contents of a meta-config file into its destination config file
77
+# If configfile does not exist it will be created.
78
+# merge_config_file infile group configfile
79
+function merge_config_file() {
80
+    local file=$1
81
+    local matchgroup=$2
82
+    local configfile=$3
83
+
84
+    [[ -r $configfile ]] || touch $configfile
85
+
86
+    get_meta_section $file $matchgroup $configfile | \
87
+    $CONFIG_AWK_CMD -v configfile=$configfile '
88
+        BEGIN { section = "" }
89
+        /^\[.+\]/ {
90
+            gsub("[][]", "", $1);
91
+            section=$1
92
+            next
93
+        }
94
+        /^ *\#/ {
95
+            next
96
+        }
97
+        /^.+/ {
98
+            split($0, d, " *= *")
99
+            print "iniset " configfile " " section " " d[1] " \"" d[2] "\""
100
+        }
101
+    ' | while read a; do eval "$a"; done
102
+
103
+}
104
+
105
+
106
+# Merge all of the files specified by group
107
+# merge_config_group infile group [group ...]
108
+function merge_config_group() {
109
+    local localfile=$1; shift
110
+    local matchgroups=$@
111
+
112
+    [[ -r $localfile ]] || return 0
113
+
114
+    for group in $matchgroups; do
115
+        for configfile in $(get_meta_section_files $localfile $group); do
116
+            if [[ -d $(dirname $configfile) ]]; then
117
+                merge_config_file $localfile $group $configfile
118
+            fi
119
+        done
120
+    done
121
+}
122
+
123
+
124
+# Restore xtrace
125
+$C_XTRACE
126
+
127
+# Local variables:
128
+# mode: shell-script
129
+# End:
... ...
@@ -29,6 +29,9 @@ TOP_DIR=$(cd $(dirname "$0") && pwd)
29 29
 # Import common functions
30 30
 source $TOP_DIR/functions
31 31
 
32
+# Import config functions
33
+source $TOP_DIR/lib/config
34
+
32 35
 # Determine what system we are running on.  This provides ``os_VENDOR``,
33 36
 # ``os_RELEASE``, ``os_UPDATE``, ``os_PACKAGE``, ``os_CODENAME``
34 37
 # and ``DISTRO``
... ...
@@ -38,6 +41,25 @@ GetDistro
38 38
 # Global Settings
39 39
 # ===============
40 40
 
41
+# Check for a ``localrc`` section embedded in ``local.conf`` and extract if
42
+# ``localrc`` does not already exist
43
+
44
+# Phase: local
45
+rm -f $TOP_DIR/.localrc.auto
46
+if [[ -r $TOP_DIR/local.conf ]]; then
47
+    LRC=$(get_meta_section_files $TOP_DIR/local.conf local)
48
+    for lfile in $LRC; do
49
+        if [[ "$lfile" == "localrc" ]]; then
50
+            if [[ -r $TOP_DIR/localrc ]]; then
51
+                warn $LINENO "localrc and local.conf:[[local]] both exist, using localrc"
52
+            else
53
+                echo "# Generated file, do not exit" >$TOP_DIR/.localrc.auto
54
+                get_meta_section $TOP_DIR/local.conf local $lfile >>$TOP_DIR/.localrc.auto
55
+            fi
56
+        fi
57
+    done
58
+fi
59
+
41 60
 # ``stack.sh`` is customizable by setting environment variables.  Override a
42 61
 # default setting via export::
43 62
 #
... ...
@@ -812,6 +834,9 @@ if is_service_enabled sysstat;then
812 812
 fi
813 813
 
814 814
 
815
+# Start Services
816
+# ==============
817
+
815 818
 # Keystone
816 819
 # --------
817 820
 
... ...
@@ -1068,6 +1093,14 @@ if is_service_enabled nova && is_baremetal; then
1068 1068
 fi
1069 1069
 
1070 1070
 
1071
+# Local Configuration
1072
+# ===================
1073
+
1074
+# Apply configuration from local.conf if it exists for layer 2 services
1075
+# Phase: post-config
1076
+merge_config_group $TOP_DIR/local.conf post-config
1077
+
1078
+
1071 1079
 # Launch Services
1072 1080
 # ===============
1073 1081
 
... ...
@@ -1263,6 +1296,14 @@ for i in BASE_SQL_CONN ENABLED_SERVICES HOST_IP LOGFILE \
1263 1263
 done
1264 1264
 
1265 1265
 
1266
+# Local Configuration
1267
+# ===================
1268
+
1269
+# Apply configuration from local.conf if it exists for layer 2 services
1270
+# Phase: extra
1271
+merge_config_group $TOP_DIR/local.conf extra
1272
+
1273
+
1266 1274
 # Run extras
1267 1275
 # ==========
1268 1276
 
... ...
@@ -1335,5 +1376,66 @@ if [[ -n "$DEPRECATED_TEXT" ]]; then
1335 1335
     echo_summary "WARNING: $DEPRECATED_TEXT"
1336 1336
 fi
1337 1337
 
1338
+# Specific warning for deprecated configs
1339
+if [[ -n "$EXTRA_OPTS" ]]; then
1340
+    echo ""
1341
+    echo_summary "WARNING: EXTRA_OPTS is used"
1342
+    echo "You are using EXTRA_OPTS to pass configuration into nova.conf."
1343
+    echo "Please convert that configuration in localrc to a nova.conf section in local.conf:"
1344
+    echo "
1345
+[[post-config|\$NOVA_CONF]]
1346
+[DEFAULT]
1347
+"
1348
+    for I in "${EXTRA_OPTS[@]}"; do
1349
+        # Replace the first '=' with ' ' for iniset syntax
1350
+        echo ${I}
1351
+    done
1352
+fi
1353
+
1354
+if [[ -n "$EXTRA_BAREMETAL_OPTS" ]]; then
1355
+    echo ""
1356
+    echo_summary "WARNING: EXTRA_OPTS is used"
1357
+    echo "You are using EXTRA_OPTS to pass configuration into nova.conf."
1358
+    echo "Please convert that configuration in localrc to a nova.conf section in local.conf:"
1359
+    echo "
1360
+[[post-config|\$NOVA_CONF]]
1361
+[baremetal]
1362
+"
1363
+    for I in "${EXTRA_BAREMETAL_OPTS[@]}"; do
1364
+        # Replace the first '=' with ' ' for iniset syntax
1365
+        echo ${I}
1366
+    done
1367
+fi
1368
+
1369
+if [[ -n "$Q_DHCP_EXTRA_DEFAULT_OPTS" ]]; then
1370
+    echo ""
1371
+    echo_summary "WARNING: Q_DHCP_EXTRA_DEFAULT_OPTS is used"
1372
+    echo "You are using Q_DHCP_EXTRA_DEFAULT_OPTS to pass configuration into $Q_DHCP_CONF_FILE."
1373
+    echo "Please convert that configuration in localrc to a $Q_DHCP_CONF_FILE section in local.conf:"
1374
+    echo "
1375
+[[post-config|\$Q_DHCP_CONF_FILE]]
1376
+[DEFAULT]
1377
+"
1378
+    for I in "${Q_DHCP_EXTRA_DEFAULT_OPTS[@]}"; do
1379
+        # Replace the first '=' with ' ' for iniset syntax
1380
+        echo ${I}
1381
+    done
1382
+fi
1383
+
1384
+if [[ -n "$Q_SRV_EXTRA_DEFAULT_OPTS" ]]; then
1385
+    echo ""
1386
+    echo_summary "WARNING: Q_SRV_EXTRA_DEFAULT_OPTS is used"
1387
+    echo "You are using Q_SRV_EXTRA_DEFAULT_OPTS to pass configuration into $NEUTRON_CONF."
1388
+    echo "Please convert that configuration in localrc to a $NEUTRON_CONF section in local.conf:"
1389
+    echo "
1390
+[[post-config|\$NEUTRON_CONF]]
1391
+[DEFAULT]
1392
+"
1393
+    for I in "${Q_SRV_EXTRA_DEFAULT_OPTS[@]}"; do
1394
+        # Replace the first '=' with ' ' for iniset syntax
1395
+        echo ${I}
1396
+    done
1397
+fi
1398
+
1338 1399
 # Indicate how long this took to run (bash maintained variable ``SECONDS``)
1339 1400
 echo_summary "stack.sh completed in $SECONDS seconds."
... ...
@@ -48,8 +48,12 @@ IDENTITY_API_VERSION=2.0
48 48
 USE_SCREEN=True
49 49
 
50 50
 # allow local overrides of env variables, including repo config
51
-if [ -f $RC_DIR/localrc ]; then
51
+if [[ -f $RC_DIR/localrc ]]; then
52
+    # Old-style user-supplied config
52 53
     source $RC_DIR/localrc
54
+elif [[ -f $RC_DIR/.localrc.auto ]]; then
55
+    # New-style user-supplied config extracted from local.conf
56
+    source $RC_DIR/.localrc.auto
53 57
 fi
54 58
 
55 59
 
56 60
new file mode 100755
... ...
@@ -0,0 +1,179 @@
0
+#!/usr/bin/env bash
1
+
2
+# Tests for DevStack meta-config functions
3
+
4
+TOP=$(cd $(dirname "$0")/.. && pwd)
5
+
6
+# Import common functions
7
+source $TOP/functions
8
+
9
+# Import config functions
10
+source $TOP/lib/config
11
+
12
+# check_result() tests and reports the result values
13
+# check_result "actual" "expected"
14
+function check_result() {
15
+    local actual=$1
16
+    local expected=$2
17
+    if [[ "$actual" == "$expected" ]]; then
18
+        echo "OK"
19
+    else
20
+        echo -e "failed: $actual != $expected\n"
21
+    fi
22
+}
23
+
24
+TEST_1C_ADD="[eee]
25
+type=new
26
+multi = foo2"
27
+
28
+function create_test1c() {
29
+    cat >test1c.conf <<EOF
30
+[eee]
31
+# original comment
32
+type=original
33
+EOF
34
+}
35
+
36
+function create_test2a() {
37
+    cat >test2a.conf <<EOF
38
+[ddd]
39
+# original comment
40
+type=original
41
+EOF
42
+}
43
+
44
+cat >test.conf <<EOF
45
+[[test1|test1a.conf]]
46
+[default]
47
+# comment an option
48
+#log_file=./log.conf
49
+log_file=/etc/log.conf
50
+handlers=do not disturb
51
+
52
+[aaa]
53
+# the commented option should not change
54
+#handlers=cc,dd
55
+handlers = aa, bb
56
+
57
+[[test1|test1b.conf]]
58
+[bbb]
59
+handlers=ee,ff
60
+
61
+[ ccc ]
62
+spaces  =  yes
63
+
64
+[[test2|test2a.conf]]
65
+[ddd]
66
+# new comment
67
+type=new
68
+additional=true
69
+
70
+[[test1|test1c.conf]]
71
+$TEST_1C_ADD
72
+EOF
73
+
74
+
75
+echo -n "get_meta_section_files: test0 doesn't exist: "
76
+VAL=$(get_meta_section_files test.conf test0)
77
+check_result "$VAL" ""
78
+
79
+echo -n "get_meta_section_files: test1 3 files: "
80
+VAL=$(get_meta_section_files test.conf test1)
81
+EXPECT_VAL="test1a.conf
82
+test1b.conf
83
+test1c.conf"
84
+check_result "$VAL" "$EXPECT_VAL"
85
+
86
+echo -n "get_meta_section_files: test2 1 file: "
87
+VAL=$(get_meta_section_files test.conf test2)
88
+EXPECT_VAL="test2a.conf"
89
+check_result "$VAL" "$EXPECT_VAL"
90
+
91
+
92
+# Get a section from a group that doesn't exist
93
+echo -n "get_meta_section: test0 doesn't exist: "
94
+VAL=$(get_meta_section test.conf test0 test0.conf)
95
+check_result "$VAL" ""
96
+
97
+# Get a single section from a group with multiple files
98
+echo -n "get_meta_section: test1c single section: "
99
+VAL=$(get_meta_section test.conf test1 test1c.conf)
100
+check_result "$VAL" "$TEST_1C_ADD"
101
+
102
+# Get a single section from a group with a single file
103
+echo -n "get_meta_section: test2a single section: "
104
+VAL=$(get_meta_section test.conf test2 test2a.conf)
105
+EXPECT_VAL="[ddd]
106
+# new comment
107
+type=new
108
+additional=true"
109
+check_result "$VAL" "$EXPECT_VAL"
110
+
111
+# Get a single section that doesn't exist from a group
112
+echo -n "get_meta_section: test2z.conf not in test2: "
113
+VAL=$(get_meta_section test.conf test2 test2z.conf)
114
+check_result "$VAL" ""
115
+
116
+# Get a section from a conf file that doesn't exist
117
+echo -n "get_meta_section: nofile doesn't exist: "
118
+VAL=$(get_meta_section nofile.ini test1)
119
+check_result "$VAL" ""
120
+
121
+echo -n "get_meta_section: nofile doesn't exist: "
122
+VAL=$(get_meta_section nofile.ini test0 test0.conf)
123
+check_result "$VAL" ""
124
+
125
+echo -n "merge_config_file test1c exists: "
126
+create_test1c
127
+merge_config_file test.conf test1 test1c.conf
128
+VAL=$(cat test1c.conf)
129
+# iniset adds values immediately under the section header
130
+EXPECT_VAL="[eee]
131
+multi = foo2
132
+# original comment
133
+type=new"
134
+check_result "$VAL" "$EXPECT_VAL"
135
+
136
+echo -n "merge_config_file test2a exists: "
137
+create_test2a
138
+merge_config_file test.conf test2 test2a.conf
139
+VAL=$(cat test2a.conf)
140
+# iniset adds values immediately under the section header
141
+EXPECT_VAL="[ddd]
142
+additional = true
143
+# original comment
144
+type=new"
145
+check_result "$VAL" "$EXPECT_VAL"
146
+
147
+echo -n "merge_config_file test2a not exist: "
148
+rm test2a.conf
149
+merge_config_file test.conf test2 test2a.conf
150
+VAL=$(cat test2a.conf)
151
+# iniset adds a blank line if it creates the file...
152
+EXPECT_VAL="
153
+[ddd]
154
+additional = true
155
+type = new"
156
+check_result "$VAL" "$EXPECT_VAL"
157
+
158
+echo -n "merge_config_group test2: "
159
+rm test2a.conf
160
+merge_config_group test.conf test2
161
+VAL=$(cat test2a.conf)
162
+# iniset adds a blank line if it creates the file...
163
+EXPECT_VAL="
164
+[ddd]
165
+additional = true
166
+type = new"
167
+check_result "$VAL" "$EXPECT_VAL"
168
+
169
+echo -n "merge_config_group test2 no conf file: "
170
+rm test2a.conf
171
+merge_config_group x-test.conf test2
172
+if [[ ! -r test2a.conf ]]; then
173
+    echo "OK"
174
+else
175
+    echo "failed: $VAL != $EXPECT_VAL"
176
+fi
177
+
178
+rm -f test.conf test1c.conf test2a.conf