From 85ea344d4ba3da78d0ca8c707c576fb54d4b1fd7 Mon Sep 17 00:00:00 2001
From: Harm Weites <harm@weites.com>
Date: Thu, 2 Jul 2015 20:50:23 +0200
Subject: [PATCH] Add config-internal/config-external to Neutron containers

Partially Implements: Blueprint standard-start

Change-Id: Ic7334c1bed2a2b5055bd5c1e39b9f9ac32c30c6a
---
 .../neutron-dhcp-agent/config-external.sh     |   1 +
 .../neutron-dhcp-agent/config-internal.sh     |   1 +
 .../neutron-l3-agent/config-external.sh       |   1 +
 .../neutron-l3-agent/config-internal.sh       |   1 +
 .../neutron-metadata-agent/config-external.sh |   1 +
 .../neutron-metadata-agent/config-internal.sh |   1 +
 .../neutron-linuxbridge-agent/Dockerfile      |   2 +
 .../config-external.sh                        |   1 +
 .../config-internal.sh                        |   1 +
 .../neutron-openvswitch-agent/Dockerfile      |   2 +
 .../config-external.sh                        |   1 +
 .../config-internal.sh                        |   1 +
 .../binary/neutron/neutron-server/Dockerfile  |   1 +
 .../neutron/neutron-server/config-external.sh |   1 +
 .../neutron/neutron-server/config-internal.sh |   1 +
 .../neutron-dhcp-agent/config-external.sh     |  13 ++
 .../neutron-dhcp-agent/config-internal.sh     |  94 ++++++++++++++
 .../neutron/neutron-dhcp-agent/start.sh       | 120 +++++-------------
 .../neutron-l3-agent/config-external.sh       |  13 ++
 .../neutron-l3-agent/config-internal.sh       |  91 +++++++++++++
 .../common/neutron/neutron-l3-agent/start.sh  | 117 +++++------------
 .../config-external.sh                        |  10 ++
 .../config-internal.sh                        |  29 +++++
 .../neutron-linuxbridge-agent/start.sh        |  32 ++---
 .../neutron-metadata-agent/config-external.sh |  13 ++
 .../neutron-metadata-agent/config-internal.sh |  74 +++++++++++
 .../neutron/neutron-metadata-agent/start.sh   | 100 +++++----------
 .../config-external.sh                        |  10 ++
 .../config-internal.sh                        |  45 +++++++
 .../neutron-openvswitch-agent/start.sh        |  48 ++-----
 .../neutron/neutron-server/config-external.sh |  10 ++
 .../neutron/neutron-server/config-internal.sh |  98 ++++++++++++++
 docker/common/neutron/neutron-server/start.sh | 104 ++-------------
 33 files changed, 645 insertions(+), 393 deletions(-)
 create mode 120000 docker/centos/binary/neutron/neutron-agents/neutron-dhcp-agent/config-external.sh
 create mode 120000 docker/centos/binary/neutron/neutron-agents/neutron-dhcp-agent/config-internal.sh
 create mode 120000 docker/centos/binary/neutron/neutron-agents/neutron-l3-agent/config-external.sh
 create mode 120000 docker/centos/binary/neutron/neutron-agents/neutron-l3-agent/config-internal.sh
 create mode 120000 docker/centos/binary/neutron/neutron-agents/neutron-metadata-agent/config-external.sh
 create mode 120000 docker/centos/binary/neutron/neutron-agents/neutron-metadata-agent/config-internal.sh
 create mode 120000 docker/centos/binary/neutron/neutron-linuxbridge-agent/config-external.sh
 create mode 120000 docker/centos/binary/neutron/neutron-linuxbridge-agent/config-internal.sh
 create mode 120000 docker/centos/binary/neutron/neutron-openvswitch-agent/config-external.sh
 create mode 120000 docker/centos/binary/neutron/neutron-openvswitch-agent/config-internal.sh
 create mode 120000 docker/centos/binary/neutron/neutron-server/config-external.sh
 create mode 120000 docker/centos/binary/neutron/neutron-server/config-internal.sh
 create mode 100755 docker/common/neutron/neutron-dhcp-agent/config-external.sh
 create mode 100755 docker/common/neutron/neutron-dhcp-agent/config-internal.sh
 create mode 100755 docker/common/neutron/neutron-l3-agent/config-external.sh
 create mode 100755 docker/common/neutron/neutron-l3-agent/config-internal.sh
 create mode 100755 docker/common/neutron/neutron-linuxbridge-agent/config-external.sh
 create mode 100755 docker/common/neutron/neutron-linuxbridge-agent/config-internal.sh
 create mode 100755 docker/common/neutron/neutron-metadata-agent/config-external.sh
 create mode 100755 docker/common/neutron/neutron-metadata-agent/config-internal.sh
 create mode 100755 docker/common/neutron/neutron-openvswitch-agent/config-external.sh
 create mode 100755 docker/common/neutron/neutron-openvswitch-agent/config-internal.sh
 create mode 100755 docker/common/neutron/neutron-server/config-external.sh
 create mode 100755 docker/common/neutron/neutron-server/config-internal.sh

diff --git a/docker/centos/binary/neutron/neutron-agents/neutron-dhcp-agent/config-external.sh b/docker/centos/binary/neutron/neutron-agents/neutron-dhcp-agent/config-external.sh
new file mode 120000
index 0000000000..680eee8757
--- /dev/null
+++ b/docker/centos/binary/neutron/neutron-agents/neutron-dhcp-agent/config-external.sh
@@ -0,0 +1 @@
+../../../../../common/neutron/neutron-dhcp-agent/config-external.sh
\ No newline at end of file
diff --git a/docker/centos/binary/neutron/neutron-agents/neutron-dhcp-agent/config-internal.sh b/docker/centos/binary/neutron/neutron-agents/neutron-dhcp-agent/config-internal.sh
new file mode 120000
index 0000000000..65cd887042
--- /dev/null
+++ b/docker/centos/binary/neutron/neutron-agents/neutron-dhcp-agent/config-internal.sh
@@ -0,0 +1 @@
+../../../../../common/neutron/neutron-dhcp-agent/config-internal.sh
\ No newline at end of file
diff --git a/docker/centos/binary/neutron/neutron-agents/neutron-l3-agent/config-external.sh b/docker/centos/binary/neutron/neutron-agents/neutron-l3-agent/config-external.sh
new file mode 120000
index 0000000000..f4530afd99
--- /dev/null
+++ b/docker/centos/binary/neutron/neutron-agents/neutron-l3-agent/config-external.sh
@@ -0,0 +1 @@
+../../../../../common/neutron/neutron-l3-agent/config-external.sh
\ No newline at end of file
diff --git a/docker/centos/binary/neutron/neutron-agents/neutron-l3-agent/config-internal.sh b/docker/centos/binary/neutron/neutron-agents/neutron-l3-agent/config-internal.sh
new file mode 120000
index 0000000000..73c2ccb551
--- /dev/null
+++ b/docker/centos/binary/neutron/neutron-agents/neutron-l3-agent/config-internal.sh
@@ -0,0 +1 @@
+../../../../../common/neutron/neutron-l3-agent/config-internal.sh
\ No newline at end of file
diff --git a/docker/centos/binary/neutron/neutron-agents/neutron-metadata-agent/config-external.sh b/docker/centos/binary/neutron/neutron-agents/neutron-metadata-agent/config-external.sh
new file mode 120000
index 0000000000..a5c3ac24a0
--- /dev/null
+++ b/docker/centos/binary/neutron/neutron-agents/neutron-metadata-agent/config-external.sh
@@ -0,0 +1 @@
+../../../../../common/neutron/neutron-metadata-agent/config-external.sh
\ No newline at end of file
diff --git a/docker/centos/binary/neutron/neutron-agents/neutron-metadata-agent/config-internal.sh b/docker/centos/binary/neutron/neutron-agents/neutron-metadata-agent/config-internal.sh
new file mode 120000
index 0000000000..23d60c52f8
--- /dev/null
+++ b/docker/centos/binary/neutron/neutron-agents/neutron-metadata-agent/config-internal.sh
@@ -0,0 +1 @@
+../../../../../common/neutron/neutron-metadata-agent/config-internal.sh
\ No newline at end of file
diff --git a/docker/centos/binary/neutron/neutron-linuxbridge-agent/Dockerfile b/docker/centos/binary/neutron/neutron-linuxbridge-agent/Dockerfile
index 702e16b42b..1ad5d82f39 100644
--- a/docker/centos/binary/neutron/neutron-linuxbridge-agent/Dockerfile
+++ b/docker/centos/binary/neutron/neutron-linuxbridge-agent/Dockerfile
@@ -7,4 +7,6 @@ RUN yum install -y openstack-neutron-linuxbridge && \
 
 COPY check.sh start.sh /
 
+COPY config-internal.sh config-external.sh /opt/kolla/
+
 CMD ["/start.sh"]
diff --git a/docker/centos/binary/neutron/neutron-linuxbridge-agent/config-external.sh b/docker/centos/binary/neutron/neutron-linuxbridge-agent/config-external.sh
new file mode 120000
index 0000000000..6bd77d67dc
--- /dev/null
+++ b/docker/centos/binary/neutron/neutron-linuxbridge-agent/config-external.sh
@@ -0,0 +1 @@
+../../../../common/neutron/neutron-linuxbridge-agent/config-external.sh
\ No newline at end of file
diff --git a/docker/centos/binary/neutron/neutron-linuxbridge-agent/config-internal.sh b/docker/centos/binary/neutron/neutron-linuxbridge-agent/config-internal.sh
new file mode 120000
index 0000000000..faacbd3ed9
--- /dev/null
+++ b/docker/centos/binary/neutron/neutron-linuxbridge-agent/config-internal.sh
@@ -0,0 +1 @@
+../../../../common/neutron/neutron-linuxbridge-agent/config-internal.sh
\ No newline at end of file
diff --git a/docker/centos/binary/neutron/neutron-openvswitch-agent/Dockerfile b/docker/centos/binary/neutron/neutron-openvswitch-agent/Dockerfile
index 551d81a539..b18ec9d203 100644
--- a/docker/centos/binary/neutron/neutron-openvswitch-agent/Dockerfile
+++ b/docker/centos/binary/neutron/neutron-openvswitch-agent/Dockerfile
@@ -8,4 +8,6 @@ RUN yum install -y openstack-neutron-openvswitch \
 
 COPY check.sh start.sh /
 
+COPY config-internal.sh config-external.sh /opt/kolla/
+
 CMD ["/start.sh"]
diff --git a/docker/centos/binary/neutron/neutron-openvswitch-agent/config-external.sh b/docker/centos/binary/neutron/neutron-openvswitch-agent/config-external.sh
new file mode 120000
index 0000000000..14354b71a0
--- /dev/null
+++ b/docker/centos/binary/neutron/neutron-openvswitch-agent/config-external.sh
@@ -0,0 +1 @@
+../../../../common/neutron/neutron-openvswitch-agent/config-external.sh
\ No newline at end of file
diff --git a/docker/centos/binary/neutron/neutron-openvswitch-agent/config-internal.sh b/docker/centos/binary/neutron/neutron-openvswitch-agent/config-internal.sh
new file mode 120000
index 0000000000..1d7c6c6bff
--- /dev/null
+++ b/docker/centos/binary/neutron/neutron-openvswitch-agent/config-internal.sh
@@ -0,0 +1 @@
+../../../../common/neutron/neutron-openvswitch-agent/config-internal.sh
\ No newline at end of file
diff --git a/docker/centos/binary/neutron/neutron-server/Dockerfile b/docker/centos/binary/neutron/neutron-server/Dockerfile
index 0bfd3cf4b3..75f7c066f9 100644
--- a/docker/centos/binary/neutron/neutron-server/Dockerfile
+++ b/docker/centos/binary/neutron/neutron-server/Dockerfile
@@ -6,5 +6,6 @@ RUN yum install -y which && \
     yum clean all
 
 COPY check.sh start.sh /
+COPY config-internal.sh config-external.sh /opt/kolla/
 
 CMD ["/start.sh"]
diff --git a/docker/centos/binary/neutron/neutron-server/config-external.sh b/docker/centos/binary/neutron/neutron-server/config-external.sh
new file mode 120000
index 0000000000..b8d7792ced
--- /dev/null
+++ b/docker/centos/binary/neutron/neutron-server/config-external.sh
@@ -0,0 +1 @@
+../../../../common/neutron/neutron-server/config-external.sh
\ No newline at end of file
diff --git a/docker/centos/binary/neutron/neutron-server/config-internal.sh b/docker/centos/binary/neutron/neutron-server/config-internal.sh
new file mode 120000
index 0000000000..6c3a8a112b
--- /dev/null
+++ b/docker/centos/binary/neutron/neutron-server/config-internal.sh
@@ -0,0 +1 @@
+../../../../common/neutron/neutron-server/config-internal.sh
\ No newline at end of file
diff --git a/docker/common/neutron/neutron-dhcp-agent/config-external.sh b/docker/common/neutron/neutron-dhcp-agent/config-external.sh
new file mode 100755
index 0000000000..ccf5cbe78a
--- /dev/null
+++ b/docker/common/neutron/neutron-dhcp-agent/config-external.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+SOURCES="/opt/kolla/neutron-dhcp-agent/neutron.conf /opt/kolla/neutron-dhcp-agent/dhcp_agent.ini /opt/kolla/neutron-dhcp-agent/dnsmasq.conf"
+TARGET="/etc/neutron/"
+OWNER="neutron"
+
+for f in $SOURCES; do
+    if [[ -f "$f" ]]; then
+        fname=$(basename $f)
+        cp $f $TARGET
+        chown ${OWNER}: $TARGET/$fname
+        chmod 0644 $TARGET/$fname
+    fi
+done
diff --git a/docker/common/neutron/neutron-dhcp-agent/config-internal.sh b/docker/common/neutron/neutron-dhcp-agent/config-internal.sh
new file mode 100755
index 0000000000..37182ebcac
--- /dev/null
+++ b/docker/common/neutron/neutron-dhcp-agent/config-internal.sh
@@ -0,0 +1,94 @@
+#!/bin/bash
+
+set -e
+
+. /opt/kolla/config-neutron.sh
+. /opt/kolla/config-sudoers.sh
+
+: ${DHCP_DRIVER:=neutron.agent.linux.dhcp.Dnsmasq}
+: ${USE_NAMESPACES:=true}
+: ${DELETE_NAMESPACES:=true}
+: ${DNSMASQ_CONFIG_FILE:=/etc/neutron/dnsmasq/dnsmasq-neutron.conf}
+: ${ROOT_HELPER:=sudo neutron-rootwrap /etc/neutron/rootwrap.conf}
+
+mkdir -p $(dirname $DNSMASQ_CONFIG_FILE)
+
+check_required_vars VERBOSE_LOGGING DEBUG_LOGGING MECHANISM_DRIVERS \
+                    DHCP_DRIVER USE_NAMESPACES DELETE_NAMESPACES \
+                    NEUTRON_LOG_DIR DNSMASQ_CONFIG_FILE \
+
+cfg=/etc/neutron/dhcp_agent.ini
+neutron_conf=/etc/neutron/neutron.conf
+
+# Workaround bug in dhclient in cirros images which does not correctly
+# handle setting checksums of packets when using hardware with checksum
+# offloading.  See:
+# https://www.rdoproject.org/forum/discussion/567/packstack-allinone-grizzly-cirros-image-cannot-get-a-dhcp-address-when-a-centos-image-can/p1
+
+/usr/sbin/iptables -A POSTROUTING -t mangle -p udp --dport bootpc \
+    -j CHECKSUM --checksum-fill
+
+if [[ ${MECHANISM_DRIVERS} =~ linuxbridge ]]; then
+    interface_driver="neutron.agent.linux.interface.BridgeInterfaceDriver"
+elif [[ ${MECHANISM_DRIVERS} == "openvswitch" ]]; then
+    interface_driver="neutron.agent.linux.interface.OVSInterfaceDriver"
+fi
+
+# Logging
+crudini --set $neutron_conf \
+    DEFAULT \
+    log_file \
+    "${NEUTRON_DHCP_AGENT_LOG_FILE}"
+
+# Configure dhcp_agent.ini
+crudini --set $cfg \
+    DEFAULT \
+    verbose \
+    "${VERBOSE_LOGGING}"
+crudini --set $cfg \
+    DEFAULT \
+    debug \
+    "${DEBUG_LOGGING}"
+crudini --set $cfg \
+    DEFAULT \
+    interface_driver \
+    "$interface_driver"
+crudini --set $cfg \
+    DEFAULT \
+    dhcp_driver \
+    "${DHCP_DRIVER}"
+crudini --set $cfg \
+    DEFAULT \
+    use_namespaces \
+    "${USE_NAMESPACES}"
+crudini --set $cfg \
+    DEFAULT \
+    delete_namespaces \
+    "${DELETE_NAMESPACES}"
+crudini --set $cfg \
+    DEFAULT \
+    dnsmasq_config_file \
+    "${DNSMASQ_CONFIG_FILE}"
+crudini --set $cfg \
+    DEFAULT \
+    root_helper \
+    "${ROOT_HELPER}"
+
+cat > ${DNSMASQ_CONFIG_FILE} <<EOF
+dhcp-option-force=26,1450
+log-facility=${NEUTRON_LOG_DIR}/neutron-dnsmasq.log
+EOF
+
+# TODO: SamYaple remove this section for thin neutron containers
+# The reason we remove existing namespaces is because network namespaces don't
+# persist between container restarts because the network proc mountpoint dies
+# when the container mount namespace dies. The mountpoint in /run/netns does
+# persist however, and that is all we are cleaning up here.
+
+# Remove any existing qdhcp namespaces
+ip netns list | grep qdhcp | while read -r line ; do
+    ip netns delete $line
+done
+
+# Start DHCP Agent
+exec /usr/bin/neutron-dhcp-agent --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/dhcp_agent.ini --config-dir /etc/neutron
diff --git a/docker/common/neutron/neutron-dhcp-agent/start.sh b/docker/common/neutron/neutron-dhcp-agent/start.sh
index 37182ebcac..a89aaf6044 100755
--- a/docker/common/neutron/neutron-dhcp-agent/start.sh
+++ b/docker/common/neutron/neutron-dhcp-agent/start.sh
@@ -1,94 +1,40 @@
 #!/bin/bash
+set -o errexit
 
-set -e
+CMD="/usr/bin/neutron-dhcp-agent"
+ARGS="--config-file /etc/neutron/dhcp_agent.ini --config-dir /etc/neutron"
 
-. /opt/kolla/config-neutron.sh
-. /opt/kolla/config-sudoers.sh
+# Loading common functions.
+source /opt/kolla/kolla-common.sh
 
-: ${DHCP_DRIVER:=neutron.agent.linux.dhcp.Dnsmasq}
-: ${USE_NAMESPACES:=true}
-: ${DELETE_NAMESPACES:=true}
-: ${DNSMASQ_CONFIG_FILE:=/etc/neutron/dnsmasq/dnsmasq-neutron.conf}
-: ${ROOT_HELPER:=sudo neutron-rootwrap /etc/neutron/rootwrap.conf}
+# Override set_configs() here because it doesn't work for fat containers like
+# this one.
+set_configs() {
+    case $KOLLA_CONFIG_STRATEGY in
+        CONFIG_INTERNAL)
+            # exec is intentional to preserve existing behaviour
+            exec /opt/kolla/neutron-dhcp-agent/config-internal.sh
+            ;;
+        CONFIG_EXTERNAL_COPY_ALWAYS)
+            source /opt/kolla/neutron-dhcp-agent/config-exernal.sh
+            ;;
+        CONFIG_EXTERNAL_COPY_ONCE)
+            if [[ -f /configured-dhcp ]]; then
+                echo 'INFO - Neutron-dhcp has already been configured; Refusing to copy new configs'
+                return
+            fi
+            source /opt/kolla/neutron-dhcp-agent/config-exernal.sh
+            touch /configured-dhcp
+            ;;
 
-mkdir -p $(dirname $DNSMASQ_CONFIG_FILE)
+        *)
+            echo '$KOLLA_CONFIG_STRATEGY is not set properly'
+            exit 1
+            ;;
+    esac
+}
 
-check_required_vars VERBOSE_LOGGING DEBUG_LOGGING MECHANISM_DRIVERS \
-                    DHCP_DRIVER USE_NAMESPACES DELETE_NAMESPACES \
-                    NEUTRON_LOG_DIR DNSMASQ_CONFIG_FILE \
+# Config-internal script exec out of this function, it does not return here.
+set_configs
 
-cfg=/etc/neutron/dhcp_agent.ini
-neutron_conf=/etc/neutron/neutron.conf
-
-# Workaround bug in dhclient in cirros images which does not correctly
-# handle setting checksums of packets when using hardware with checksum
-# offloading.  See:
-# https://www.rdoproject.org/forum/discussion/567/packstack-allinone-grizzly-cirros-image-cannot-get-a-dhcp-address-when-a-centos-image-can/p1
-
-/usr/sbin/iptables -A POSTROUTING -t mangle -p udp --dport bootpc \
-    -j CHECKSUM --checksum-fill
-
-if [[ ${MECHANISM_DRIVERS} =~ linuxbridge ]]; then
-    interface_driver="neutron.agent.linux.interface.BridgeInterfaceDriver"
-elif [[ ${MECHANISM_DRIVERS} == "openvswitch" ]]; then
-    interface_driver="neutron.agent.linux.interface.OVSInterfaceDriver"
-fi
-
-# Logging
-crudini --set $neutron_conf \
-    DEFAULT \
-    log_file \
-    "${NEUTRON_DHCP_AGENT_LOG_FILE}"
-
-# Configure dhcp_agent.ini
-crudini --set $cfg \
-    DEFAULT \
-    verbose \
-    "${VERBOSE_LOGGING}"
-crudini --set $cfg \
-    DEFAULT \
-    debug \
-    "${DEBUG_LOGGING}"
-crudini --set $cfg \
-    DEFAULT \
-    interface_driver \
-    "$interface_driver"
-crudini --set $cfg \
-    DEFAULT \
-    dhcp_driver \
-    "${DHCP_DRIVER}"
-crudini --set $cfg \
-    DEFAULT \
-    use_namespaces \
-    "${USE_NAMESPACES}"
-crudini --set $cfg \
-    DEFAULT \
-    delete_namespaces \
-    "${DELETE_NAMESPACES}"
-crudini --set $cfg \
-    DEFAULT \
-    dnsmasq_config_file \
-    "${DNSMASQ_CONFIG_FILE}"
-crudini --set $cfg \
-    DEFAULT \
-    root_helper \
-    "${ROOT_HELPER}"
-
-cat > ${DNSMASQ_CONFIG_FILE} <<EOF
-dhcp-option-force=26,1450
-log-facility=${NEUTRON_LOG_DIR}/neutron-dnsmasq.log
-EOF
-
-# TODO: SamYaple remove this section for thin neutron containers
-# The reason we remove existing namespaces is because network namespaces don't
-# persist between container restarts because the network proc mountpoint dies
-# when the container mount namespace dies. The mountpoint in /run/netns does
-# persist however, and that is all we are cleaning up here.
-
-# Remove any existing qdhcp namespaces
-ip netns list | grep qdhcp | while read -r line ; do
-    ip netns delete $line
-done
-
-# Start DHCP Agent
-exec /usr/bin/neutron-dhcp-agent --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/dhcp_agent.ini --config-dir /etc/neutron
+exec $CMD $ARGS
diff --git a/docker/common/neutron/neutron-l3-agent/config-external.sh b/docker/common/neutron/neutron-l3-agent/config-external.sh
new file mode 100755
index 0000000000..5b85898b75
--- /dev/null
+++ b/docker/common/neutron/neutron-l3-agent/config-external.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+SOURCES="/opt/kolla/neutron-l3-agent/neutron.conf /opt/kolla/neutron-l3-agent/l3_agent.ini /opt/kolla/neutron-l3-agent/fwaas_driver.ini"
+TARGET="/etc/neutron/"
+OWNER="neutron"
+
+for f in $SOURCES; do
+    if [[ -f "$f" ]]; then
+        fname=$(basename $f)
+        cp $f $TARGET
+        chown ${OWNER}: $TARGET/$fname
+        chmod 0644 $TARGET/$fname
+    fi
+done
diff --git a/docker/common/neutron/neutron-l3-agent/config-internal.sh b/docker/common/neutron/neutron-l3-agent/config-internal.sh
new file mode 100755
index 0000000000..c4fb852050
--- /dev/null
+++ b/docker/common/neutron/neutron-l3-agent/config-internal.sh
@@ -0,0 +1,91 @@
+#!/bin/bash
+
+set -e
+
+. /opt/kolla/config-neutron.sh
+. /opt/kolla/config-sudoers.sh
+
+: ${USE_NAMESPACES:=true}
+
+check_required_vars VERBOSE_LOGGING DEBUG_LOGGING
+
+cfg=/etc/neutron/l3_agent.ini
+neutron_conf=/etc/neutron/neutron.conf
+
+# Logging
+crudini --set $neutron_conf \
+    DEFAULT \
+    log_file \
+    "${NEUTRON_L3_AGENT_LOG_FILE}"
+
+# Configure l3_agent.ini
+crudini --set $cfg \
+    DEFAULT \
+    verbose \
+    "${VERBOSE_LOGGING}"
+crudini --set $cfg \
+    DEFAULT \
+    debug \
+    "${DEBUG_LOGGING}"
+if [[ "${MECHANISM_DRIVERS}" =~ linuxbridge ]] ; then
+    crudini --set $cfg \
+        DEFAULT \
+        interface_driver \
+        "neutron.agent.linux.interface.BridgeInterfaceDriver"
+    crudini --set $cfg \
+        DEFAULT \
+        gateway_external_network_id \
+        ""
+    crudini --set $cfg \
+        DEFAULT \
+        external_network_bridge \
+        ""
+elif [[ "${MECHANISM_DRIVERS}" =~ .*openvswitch* ]] ; then
+    crudini --set $cfg \
+        DEFAULT \
+        interface_driver \
+        "neutron.agent.linux.interface.OVSInterfaceDriver"
+    crudini --set $cfg \
+        DEFAULT \
+        gateway_external_network_id \
+        "${NEUTRON_FLAT_NETWORK_BRIDGE}"
+    crudini --set $cfg \
+        DEFAULT \
+        external_network_bridge \
+        "${NEUTRON_FLAT_NETWORK_BRIDGE}"
+fi
+
+crudini --set $cfg \
+    DEFAULT \
+    use_namespaces \
+    "${USE_NAMESPACES}"
+
+if [ "${USE_NAMESPACES}" == "false" ] ; then
+    source /openrc
+    # Create router if it does not exist
+    /usr/bin/neutron router-list | grep admin-router || /usr/bin/neutron router-create admin-router
+    # Set router-id
+    crudini --set $cfg \
+        DEFAULT \
+        router_id \
+        "$(/usr/bin/neutron router-list | awk '/ admin-router / {print $2}')"
+elif [ "${USE_NAMESPACES}" == "true" ] ; then
+    crudini --set $cfg \
+        DEFAULT \
+        router_delete_namespaces \
+        "true"
+fi
+
+# TODO: SamYaple remove this section for thin neutron containers
+# The reason we remove existing namespaces is because network namespaces don't
+# persist between container restarts because the network proc mountpoint dies
+# when the container mount namespace dies. The mountpoint in /run/netns does
+# persist however, and that is all we are cleaning up here.
+
+# Remove any existing qrouter namespaces
+ip netns list | grep qrouter | while read -r line ; do
+    ip netns delete $line
+done
+
+# Start L3 Agent
+exec /usr/bin/neutron-l3-agent --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/l3_agent.ini --config-file /etc/neutron/fwaas_driver.ini --config-dir /etc/neutron
diff --git a/docker/common/neutron/neutron-l3-agent/start.sh b/docker/common/neutron/neutron-l3-agent/start.sh
index c4fb852050..ca301d196f 100755
--- a/docker/common/neutron/neutron-l3-agent/start.sh
+++ b/docker/common/neutron/neutron-l3-agent/start.sh
@@ -1,91 +1,40 @@
 #!/bin/bash
+set -o errexit
 
-set -e
+CMD="/usr/bin/neutron-l3-agent"
+ARGS="--config-file /etc/neutron/l3_agent.ini --config-file /etc/neutron/fwaas_driver.ini --config-dir /etc/neutron"
 
-. /opt/kolla/config-neutron.sh
-. /opt/kolla/config-sudoers.sh
+# Loading common functions.
+source /opt/kolla/kolla-common.sh
 
-: ${USE_NAMESPACES:=true}
+# Override set_configs() here because it doesn't work for fat containers like
+# this one.
+set_configs() {
+    case $KOLLA_CONFIG_STRATEGY in
+        CONFIG_INTERNAL)
+            # exec is intentional to preserve existing behaviour
+            exec /opt/kolla/neutron-l3-agent/config-internal.sh
+            ;;
+        CONFIG_EXTERNAL_COPY_ALWAYS)
+            source /opt/kolla/neutron-l3-agent/config-exernal.sh
+            ;;
+        CONFIG_EXTERNAL_COPY_ONCE)
+            if [[ -f /configured-l3 ]]; then
+                echo 'INFO - Neutron-l3 has already been configured; Refusing to copy new configs'
+                return
+            fi
+            source /opt/kolla/neutron-l3-agent/config-exernal.sh
+            touch /configured-l3
+            ;;
 
-check_required_vars VERBOSE_LOGGING DEBUG_LOGGING
+        *)
+            echo '$KOLLA_CONFIG_STRATEGY is not set properly'
+            exit 1
+            ;;
+    esac
+}
 
-cfg=/etc/neutron/l3_agent.ini
-neutron_conf=/etc/neutron/neutron.conf
+# Config-internal script exec out of this function, it does not return here.
+set_configs
 
-# Logging
-crudini --set $neutron_conf \
-    DEFAULT \
-    log_file \
-    "${NEUTRON_L3_AGENT_LOG_FILE}"
-
-# Configure l3_agent.ini
-crudini --set $cfg \
-    DEFAULT \
-    verbose \
-    "${VERBOSE_LOGGING}"
-crudini --set $cfg \
-    DEFAULT \
-    debug \
-    "${DEBUG_LOGGING}"
-if [[ "${MECHANISM_DRIVERS}" =~ linuxbridge ]] ; then
-    crudini --set $cfg \
-        DEFAULT \
-        interface_driver \
-        "neutron.agent.linux.interface.BridgeInterfaceDriver"
-    crudini --set $cfg \
-        DEFAULT \
-        gateway_external_network_id \
-        ""
-    crudini --set $cfg \
-        DEFAULT \
-        external_network_bridge \
-        ""
-elif [[ "${MECHANISM_DRIVERS}" =~ .*openvswitch* ]] ; then
-    crudini --set $cfg \
-        DEFAULT \
-        interface_driver \
-        "neutron.agent.linux.interface.OVSInterfaceDriver"
-    crudini --set $cfg \
-        DEFAULT \
-        gateway_external_network_id \
-        "${NEUTRON_FLAT_NETWORK_BRIDGE}"
-    crudini --set $cfg \
-        DEFAULT \
-        external_network_bridge \
-        "${NEUTRON_FLAT_NETWORK_BRIDGE}"
-fi
-
-crudini --set $cfg \
-    DEFAULT \
-    use_namespaces \
-    "${USE_NAMESPACES}"
-
-if [ "${USE_NAMESPACES}" == "false" ] ; then
-    source /openrc
-    # Create router if it does not exist
-    /usr/bin/neutron router-list | grep admin-router || /usr/bin/neutron router-create admin-router
-    # Set router-id
-    crudini --set $cfg \
-        DEFAULT \
-        router_id \
-        "$(/usr/bin/neutron router-list | awk '/ admin-router / {print $2}')"
-elif [ "${USE_NAMESPACES}" == "true" ] ; then
-    crudini --set $cfg \
-        DEFAULT \
-        router_delete_namespaces \
-        "true"
-fi
-
-# TODO: SamYaple remove this section for thin neutron containers
-# The reason we remove existing namespaces is because network namespaces don't
-# persist between container restarts because the network proc mountpoint dies
-# when the container mount namespace dies. The mountpoint in /run/netns does
-# persist however, and that is all we are cleaning up here.
-
-# Remove any existing qrouter namespaces
-ip netns list | grep qrouter | while read -r line ; do
-    ip netns delete $line
-done
-
-# Start L3 Agent
-exec /usr/bin/neutron-l3-agent --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/l3_agent.ini --config-file /etc/neutron/fwaas_driver.ini --config-dir /etc/neutron
+exec $CMD $ARGS
diff --git a/docker/common/neutron/neutron-linuxbridge-agent/config-external.sh b/docker/common/neutron/neutron-linuxbridge-agent/config-external.sh
new file mode 100755
index 0000000000..4e0411a9fa
--- /dev/null
+++ b/docker/common/neutron/neutron-linuxbridge-agent/config-external.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+SOURCE="/opt/kolla/neutron-linuxbridge-agent/neutron.conf"
+TARGET="/etc/neutron/neutron.conf"
+OWNER="neutron"
+
+if [[ -f "$SOURCE" ]]; then
+    cp $SOURCE $TARGET
+    chown ${OWNER}: $TARGET
+    chmod 0644 $TARGET
+fi
diff --git a/docker/common/neutron/neutron-linuxbridge-agent/config-internal.sh b/docker/common/neutron/neutron-linuxbridge-agent/config-internal.sh
new file mode 100755
index 0000000000..bd8f90194b
--- /dev/null
+++ b/docker/common/neutron/neutron-linuxbridge-agent/config-internal.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+set -e
+
+. /opt/kolla/config-neutron.sh
+. /opt/kolla/config-sudoers.sh
+
+: ${NEUTRON_FLAT_NETWORK_NAME:=physnet1}
+: ${NEUTRON_FLAT_NETWORK_INTERFACE:=eth1}
+
+check_required_vars PUBLIC_IP NEUTRON_FLAT_NETWORK_NAME \
+                    NEUTRON_FLAT_NETWORK_INTERFACE
+
+cfg=/etc/neutron/plugins/ml2/ml2_conf.ini
+
+# Configure ml2_conf.ini
+if [[ ${TYPE_DRIVERS} =~ vxlan ]]; then
+    crudini --set $cfg \
+        vxlan \
+        local_ip \
+        "${PUBLIC_IP}"
+fi
+
+crudini --set $cfg \
+    linux_bridge \
+    physical_interface_mappings \
+    "${NEUTRON_FLAT_NETWORK_NAME}:${NEUTRON_FLAT_NETWORK_INTERFACE}"
+
+exec /usr/bin/neutron-linuxbridge-agent --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugins/ml2/ml2_conf.ini --config-dir /etc/neutron
diff --git a/docker/common/neutron/neutron-linuxbridge-agent/start.sh b/docker/common/neutron/neutron-linuxbridge-agent/start.sh
index bd8f90194b..a8b4879f03 100755
--- a/docker/common/neutron/neutron-linuxbridge-agent/start.sh
+++ b/docker/common/neutron/neutron-linuxbridge-agent/start.sh
@@ -1,29 +1,13 @@
 #!/bin/bash
+set -o errexit
 
-set -e
+CMD="/usr/bin/neutron-linuxbridge-agent"
+ARGS="--config-file /etc/neutron/plugins/ml2/ml2_conf.ini --config-dir /etc/neutron"
 
-. /opt/kolla/config-neutron.sh
-. /opt/kolla/config-sudoers.sh
+# Loading common functions.
+source /opt/kolla/kolla-common.sh
 
-: ${NEUTRON_FLAT_NETWORK_NAME:=physnet1}
-: ${NEUTRON_FLAT_NETWORK_INTERFACE:=eth1}
+# Config-internal script exec out of this function, it does not return here.
+set_configs
 
-check_required_vars PUBLIC_IP NEUTRON_FLAT_NETWORK_NAME \
-                    NEUTRON_FLAT_NETWORK_INTERFACE
-
-cfg=/etc/neutron/plugins/ml2/ml2_conf.ini
-
-# Configure ml2_conf.ini
-if [[ ${TYPE_DRIVERS} =~ vxlan ]]; then
-    crudini --set $cfg \
-        vxlan \
-        local_ip \
-        "${PUBLIC_IP}"
-fi
-
-crudini --set $cfg \
-    linux_bridge \
-    physical_interface_mappings \
-    "${NEUTRON_FLAT_NETWORK_NAME}:${NEUTRON_FLAT_NETWORK_INTERFACE}"
-
-exec /usr/bin/neutron-linuxbridge-agent --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugins/ml2/ml2_conf.ini --config-dir /etc/neutron
+exec $CMD $ARGS
diff --git a/docker/common/neutron/neutron-metadata-agent/config-external.sh b/docker/common/neutron/neutron-metadata-agent/config-external.sh
new file mode 100755
index 0000000000..1d39217826
--- /dev/null
+++ b/docker/common/neutron/neutron-metadata-agent/config-external.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+SOURCES="/opt/kolla/neutron-metadata-agent/neutron.conf /opt/kolla/neutron-metadata-agent/metadata_agent.ini"
+TARGET="/etc/neutron/"
+OWNER="neutron"
+
+for f in $SOURCES; do
+    if [[ -f "$f" ]]; then
+        fname=$(basename $f)
+        cp $f $TARGET
+        chown ${OWNER}: $TARGET/$fname
+        chmod 0644 $TARGET/$fname
+    fi
+done
diff --git a/docker/common/neutron/neutron-metadata-agent/config-internal.sh b/docker/common/neutron/neutron-metadata-agent/config-internal.sh
new file mode 100755
index 0000000000..d1eef341c1
--- /dev/null
+++ b/docker/common/neutron/neutron-metadata-agent/config-internal.sh
@@ -0,0 +1,74 @@
+#!/bin/bash
+
+set -e
+
+. /opt/kolla/config-neutron.sh
+. /opt/kolla/config-sudoers.sh
+
+: ${KEYSTONE_REGION:=RegionOne}
+: ${ENDPOINT_TYPE:=adminURL}
+: ${NEUTRON_SHARED_SECRET:=sharedsecret}
+
+check_required_vars VERBOSE_LOGGING DEBUG_LOGGING KEYSTONE_AUTH_PROTOCOL \
+                    KEYSTONE_PUBLIC_SERVICE_HOST ADMIN_TENANT_NAME \
+                    NEUTRON_KEYSTONE_USER NEUTRON_KEYSTONE_PASSWORD \
+                    NEUTRON_SHARED_SECRET NOVA_METADATA_API_SERVICE_HOST \
+                    NOVA_METADATA_API_SERVICE_PORT
+
+cfg=/etc/neutron/metadata_agent.ini
+neutron_conf=/etc/neutron/neutron.conf
+
+# Logging
+crudini --set $neutron_conf \
+        DEFAULT \
+        log_file \
+        "${NEUTRON_METADATA_AGENT_LOG_FILE}"
+
+# Configure metadata_agent.ini
+crudini --set $cfg \
+        DEFAULT \
+        verbose \
+        "${VERBOSE_LOGGING}"
+crudini --set $cfg \
+        DEFAULT \
+        debug \
+        "${DEBUG_LOGGING}"
+crudini --set $cfg \
+        DEFAULT \
+        auth_region \
+        "${KEYSTONE_REGION}"
+crudini --set $cfg \
+        DEFAULT \
+        endpoint_type \
+        "${ENDPOINT_TYPE}"
+crudini --set $cfg \
+        DEFAULT \
+        auth_url \
+        "${KEYSTONE_AUTH_PROTOCOL}://${KEYSTONE_PUBLIC_SERVICE_HOST}:${KEYSTONE_PUBLIC_SERVICE_PORT}/v2.0"
+crudini --set $cfg \
+        DEFAULT \
+        admin_tenant_name \
+        "${ADMIN_TENANT_NAME}"
+crudini --set $cfg \
+        DEFAULT \
+        admin_user \
+        "${NEUTRON_KEYSTONE_USER}"
+crudini --set $cfg \
+        DEFAULT \
+        admin_password \
+        "${NEUTRON_KEYSTONE_PASSWORD}"
+crudini --set $cfg \
+        DEFAULT \
+        nova_metadata_ip \
+        "${NOVA_METADATA_API_SERVICE_HOST}"
+crudini --set $cfg \
+        DEFAULT \
+        nova_metadata_port \
+        "${NOVA_METADATA_API_SERVICE_PORT}"
+crudini --set $cfg \
+        DEFAULT \
+        metadata_proxy_shared_secret \
+        "${NEUTRON_SHARED_SECRET}"
+
+# Start Metadata Agent
+exec /usr/bin/neutron-metadata-agent --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/metadata_agent.ini --config-dir /etc/neutron
diff --git a/docker/common/neutron/neutron-metadata-agent/start.sh b/docker/common/neutron/neutron-metadata-agent/start.sh
index d1eef341c1..c43388b0c4 100755
--- a/docker/common/neutron/neutron-metadata-agent/start.sh
+++ b/docker/common/neutron/neutron-metadata-agent/start.sh
@@ -1,74 +1,40 @@
 #!/bin/bash
+set -o errexit
 
-set -e
+CMD="/usr/bin/neutron-metadata-agent"
+ARGS="--config-file /etc/neutron/metadata_agent.ini --config-dir /etc/neutron"
 
-. /opt/kolla/config-neutron.sh
-. /opt/kolla/config-sudoers.sh
+# Loading common functions.
+source /opt/kolla/kolla-common.sh
 
-: ${KEYSTONE_REGION:=RegionOne}
-: ${ENDPOINT_TYPE:=adminURL}
-: ${NEUTRON_SHARED_SECRET:=sharedsecret}
+# Override set_configs() here because it doesn't work for fat containers like
+# this one.
+set_configs() {
+    case $KOLLA_CONFIG_STRATEGY in
+        CONFIG_INTERNAL)
+            # exec is intentional to preserve existing behaviour
+            exec /opt/kolla/neutron-metadata-agent/config-internal.sh
+            ;;
+        CONFIG_EXTERNAL_COPY_ALWAYS)
+            source /opt/kolla/neutron-metadata-agent/config-exernal.sh
+            ;;
+        CONFIG_EXTERNAL_COPY_ONCE)
+            if [[ -f /configured-md ]]; then
+                echo 'INFO - Neutron-metadata has already been configured; Refusing to copy new configs'
+                return
+            fi
+            source /opt/kolla/neutron-metadata-agent/config-exernal.sh
+            touch /configured-md
+            ;;
 
-check_required_vars VERBOSE_LOGGING DEBUG_LOGGING KEYSTONE_AUTH_PROTOCOL \
-                    KEYSTONE_PUBLIC_SERVICE_HOST ADMIN_TENANT_NAME \
-                    NEUTRON_KEYSTONE_USER NEUTRON_KEYSTONE_PASSWORD \
-                    NEUTRON_SHARED_SECRET NOVA_METADATA_API_SERVICE_HOST \
-                    NOVA_METADATA_API_SERVICE_PORT
+        *)
+            echo '$KOLLA_CONFIG_STRATEGY is not set properly'
+            exit 1
+            ;;
+    esac
+}
 
-cfg=/etc/neutron/metadata_agent.ini
-neutron_conf=/etc/neutron/neutron.conf
+# Config-internal script exec out of this function, it does not return here.
+set_configs
 
-# Logging
-crudini --set $neutron_conf \
-        DEFAULT \
-        log_file \
-        "${NEUTRON_METADATA_AGENT_LOG_FILE}"
-
-# Configure metadata_agent.ini
-crudini --set $cfg \
-        DEFAULT \
-        verbose \
-        "${VERBOSE_LOGGING}"
-crudini --set $cfg \
-        DEFAULT \
-        debug \
-        "${DEBUG_LOGGING}"
-crudini --set $cfg \
-        DEFAULT \
-        auth_region \
-        "${KEYSTONE_REGION}"
-crudini --set $cfg \
-        DEFAULT \
-        endpoint_type \
-        "${ENDPOINT_TYPE}"
-crudini --set $cfg \
-        DEFAULT \
-        auth_url \
-        "${KEYSTONE_AUTH_PROTOCOL}://${KEYSTONE_PUBLIC_SERVICE_HOST}:${KEYSTONE_PUBLIC_SERVICE_PORT}/v2.0"
-crudini --set $cfg \
-        DEFAULT \
-        admin_tenant_name \
-        "${ADMIN_TENANT_NAME}"
-crudini --set $cfg \
-        DEFAULT \
-        admin_user \
-        "${NEUTRON_KEYSTONE_USER}"
-crudini --set $cfg \
-        DEFAULT \
-        admin_password \
-        "${NEUTRON_KEYSTONE_PASSWORD}"
-crudini --set $cfg \
-        DEFAULT \
-        nova_metadata_ip \
-        "${NOVA_METADATA_API_SERVICE_HOST}"
-crudini --set $cfg \
-        DEFAULT \
-        nova_metadata_port \
-        "${NOVA_METADATA_API_SERVICE_PORT}"
-crudini --set $cfg \
-        DEFAULT \
-        metadata_proxy_shared_secret \
-        "${NEUTRON_SHARED_SECRET}"
-
-# Start Metadata Agent
-exec /usr/bin/neutron-metadata-agent --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/metadata_agent.ini --config-dir /etc/neutron
+exec $CMD $ARGS
diff --git a/docker/common/neutron/neutron-openvswitch-agent/config-external.sh b/docker/common/neutron/neutron-openvswitch-agent/config-external.sh
new file mode 100755
index 0000000000..780c2be14f
--- /dev/null
+++ b/docker/common/neutron/neutron-openvswitch-agent/config-external.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+SOURCE="/opt/kolla/neutron-openvswitch-agent/neutron.conf"
+TARGET="/etc/neutron/neutron.conf"
+OWNER="neutron"
+
+if [[ -f "$SOURCE" ]]; then
+    cp $SOURCE $TARGET
+    chown ${OWNER}: $TARGET
+    chmod 0644 $TARGET
+fi
diff --git a/docker/common/neutron/neutron-openvswitch-agent/config-internal.sh b/docker/common/neutron/neutron-openvswitch-agent/config-internal.sh
new file mode 100755
index 0000000000..8c4d1a0371
--- /dev/null
+++ b/docker/common/neutron/neutron-openvswitch-agent/config-internal.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+set -e
+
+. /opt/kolla/config-neutron.sh
+. /opt/kolla/config-sudoers.sh
+
+: ${NEUTRON_FLAT_NETWORK_NAME:=physnet1}
+: ${NEUTRON_FLAT_NETWORK_INTERFACE:=eth1}
+
+check_required_vars PUBLIC_IP NEUTRON_FLAT_NETWORK_NAME \
+                    NEUTRON_FLAT_NETWORK_INTERFACE
+
+if ! ovs-vsctl show |grep ${NEUTRON_FLAT_NETWORK_INTERFACE} > /dev/null; then
+    ovs-vsctl add-br ${NEUTRON_FLAT_NETWORK_INTERFACE}
+fi
+
+cfg=/etc/neutron/plugins/openvswitch/ovs_neutron_plugin.ini
+
+# Configure ml2_conf.ini
+if [[ ${TYPE_DRIVERS} =~ vxlan ]]; then
+    crudini --set $cfg \
+        vxlan \
+        local_ip \
+        "${PUBLIC_IP}"
+fi
+
+crudini --set $cfg \
+    ovs \
+    bridge_mappings \
+    "${NEUTRON_FLAT_NETWORK_NAME}:${NEUTRON_FLAT_NETWORK_INTERFACE}"
+
+crudini --set $cfg \
+    ovs \
+    tenant_network_type \
+    "${TENANT_NETWORK_TYPES}"
+
+if [[ ${TENANT_NETWORK_TYPES} =~ "vlan" ]];then
+    crudini --set $cfg \
+        ovs \
+        network_vlan_ranges \
+        "${NEUTRON_VLAN_NETWORK_NAME}:${NEUTRON_NETWORK_VLAN_RANGES}"
+fi
+
+exec /usr/bin/neutron-openvswitch-agent --config-file /etc/neutron/neutron.conf --config-file $cfg
diff --git a/docker/common/neutron/neutron-openvswitch-agent/start.sh b/docker/common/neutron/neutron-openvswitch-agent/start.sh
index 8c4d1a0371..6c2add489f 100755
--- a/docker/common/neutron/neutron-openvswitch-agent/start.sh
+++ b/docker/common/neutron/neutron-openvswitch-agent/start.sh
@@ -1,45 +1,13 @@
 #!/bin/bash
+set -o errexit
 
-set -e
+CMD="/usr/bin/neutron-openvswitch-agent"
+ARGS="--config-file /etc/neutron/plugins/openvswitch/ovs_neutron_plugin.ini"
 
-. /opt/kolla/config-neutron.sh
-. /opt/kolla/config-sudoers.sh
+# Loading common functions.
+source /opt/kolla/kolla-common.sh
 
-: ${NEUTRON_FLAT_NETWORK_NAME:=physnet1}
-: ${NEUTRON_FLAT_NETWORK_INTERFACE:=eth1}
+# Config-internal script exec out of this function, it does not return here.
+set_configs
 
-check_required_vars PUBLIC_IP NEUTRON_FLAT_NETWORK_NAME \
-                    NEUTRON_FLAT_NETWORK_INTERFACE
-
-if ! ovs-vsctl show |grep ${NEUTRON_FLAT_NETWORK_INTERFACE} > /dev/null; then
-    ovs-vsctl add-br ${NEUTRON_FLAT_NETWORK_INTERFACE}
-fi
-
-cfg=/etc/neutron/plugins/openvswitch/ovs_neutron_plugin.ini
-
-# Configure ml2_conf.ini
-if [[ ${TYPE_DRIVERS} =~ vxlan ]]; then
-    crudini --set $cfg \
-        vxlan \
-        local_ip \
-        "${PUBLIC_IP}"
-fi
-
-crudini --set $cfg \
-    ovs \
-    bridge_mappings \
-    "${NEUTRON_FLAT_NETWORK_NAME}:${NEUTRON_FLAT_NETWORK_INTERFACE}"
-
-crudini --set $cfg \
-    ovs \
-    tenant_network_type \
-    "${TENANT_NETWORK_TYPES}"
-
-if [[ ${TENANT_NETWORK_TYPES} =~ "vlan" ]];then
-    crudini --set $cfg \
-        ovs \
-        network_vlan_ranges \
-        "${NEUTRON_VLAN_NETWORK_NAME}:${NEUTRON_NETWORK_VLAN_RANGES}"
-fi
-
-exec /usr/bin/neutron-openvswitch-agent --config-file /etc/neutron/neutron.conf --config-file $cfg
+exec $CMD $ARGS
diff --git a/docker/common/neutron/neutron-server/config-external.sh b/docker/common/neutron/neutron-server/config-external.sh
new file mode 100755
index 0000000000..83cd33ba53
--- /dev/null
+++ b/docker/common/neutron/neutron-server/config-external.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+SOURCE="/opt/kolla/neutron-server/neutron.conf"
+TARGET="/etc/neutron/neutron.conf"
+OWNER="neutron"
+
+if [[ -f "$SOURCE" ]]; then
+    cp $SOURCE $TARGET
+    chown ${OWNER}: $TARGET
+    chmod 0644 $TARGET
+fi
diff --git a/docker/common/neutron/neutron-server/config-internal.sh b/docker/common/neutron/neutron-server/config-internal.sh
new file mode 100755
index 0000000000..fb971083f5
--- /dev/null
+++ b/docker/common/neutron/neutron-server/config-internal.sh
@@ -0,0 +1,98 @@
+#!/bin/bash
+
+set -e
+
+. /opt/kolla/config-neutron.sh
+
+: ${NEUTRON_FLAT_NETWORK_NAME:=physnet1}
+: ${NEUTRON_FLAT_NETWORK_INTERFACE:=eth1}
+
+check_required_vars KEYSTONE_ADMIN_TOKEN KEYSTONE_ADMIN_SERVICE_HOST \
+                    KEYSTONE_AUTH_PROTOCOL NOVA_API_SERVICE_HOST \
+                    NOVA_KEYSTONE_USER NOVA_KEYSTONE_PASSWORD \
+                    NEUTRON_DB_NAME NEUTRON_DB_USER NEUTRON_DB_PASSWORD \
+                    NEUTRON_KEYSTONE_USER NEUTRON_KEYSTONE_PASSWORD \
+                    ADMIN_TENANT_NAME NEUTRON_SERVER_SERVICE_HOST \
+                    PUBLIC_IP NEUTRON_DB_PASSWORD
+fail_unless_os_service_running keystone
+fail_unless_db
+
+mysql -h ${MARIADB_SERVICE_HOST} -u root -p${DB_ROOT_PASSWORD} mysql <<EOF
+CREATE DATABASE IF NOT EXISTS ${NEUTRON_DB_NAME} DEFAULT CHARACTER SET utf8;
+GRANT ALL PRIVILEGES ON ${NEUTRON_DB_NAME}.* TO
+       '${NEUTRON_DB_USER}'@'%' IDENTIFIED BY '${NEUTRON_DB_PASSWORD}'
+
+EOF
+
+export SERVICE_TOKEN="${KEYSTONE_ADMIN_TOKEN}"
+export SERVICE_ENDPOINT="${KEYSTONE_AUTH_PROTOCOL}://${KEYSTONE_ADMIN_SERVICE_HOST}:${KEYSTONE_ADMIN_SERVICE_PORT}/v2.0"
+
+# Configure Keystone Service Catalog
+crux user-create -n "${NEUTRON_KEYSTONE_USER}" \
+    -p "${NEUTRON_KEYSTONE_PASSWORD}" \
+    -t "${ADMIN_TENANT_NAME}" \
+    -r admin
+
+crux endpoint-create -n neutron -t network \
+    -I "${KEYSTONE_AUTH_PROTOCOL}://${NEUTRON_SERVER_SERVICE_HOST}:${NEUTRON_SERVER_SERVICE_PORT}" \
+    -P "${KEYSTONE_AUTH_PROTOCOL}://${NEUTRON_SERVER_SERVICE_HOST}:${NEUTRON_SERVER_SERVICE_PORT}" \
+    -A "${KEYSTONE_AUTH_PROTOCOL}://${NEUTRON_SERVER_SERVICE_HOST}:${NEUTRON_SERVER_SERVICE_PORT}"
+
+core_cfg=/etc/neutron/neutron.conf
+ml2_cfg=/etc/neutron/plugins/ml2/ml2_conf.ini
+
+# Logging
+crudini --set /etc/neutron/neutron.conf \
+        DEFAULT \
+        log_file \
+        "${NEUTRON_SERVER_LOG_FILE}"
+
+# Database
+crudini --set $core_cfg \
+        database \
+        connection \
+        "mysql://${NEUTRON_DB_USER}:${NEUTRON_DB_PASSWORD}@${MARIADB_SERVICE_HOST}/${NEUTRON_DB_NAME}"
+# Nova
+crudini --set $core_cfg \
+        DEFAULT \
+        notify_nova_on_port_status_changes \
+        "True"
+crudini --set $core_cfg \
+        DEFAULT \
+        notify_nova_on_port_data_changes \
+        "True"
+crudini --set $core_cfg \
+        DEFAULT \
+        nova_url \
+        "http://${NOVA_API_SERVICE_HOST}:${NOVA_API_SERVICE_PORT}/v2"
+crudini --set $core_cfg \
+        DEFAULT \
+        nova_admin_auth_url \
+        "${KEYSTONE_AUTH_PROTOCOL}://${KEYSTONE_ADMIN_SERVICE_HOST}:${KEYSTONE_ADMIN_SERVICE_PORT}/v2.0"
+crudini --set $core_cfg \
+        DEFAULT \
+        nova_region_name \
+        "${KEYSTONE_REGION}"
+crudini --set $core_cfg \
+        DEFAULT \
+        nova_admin_username \
+        "${NOVA_KEYSTONE_USER}"
+crudini --set $core_cfg \
+        DEFAULT \
+        nova_admin_tenant_id \
+        "$(keystone tenant-list | grep $ADMIN_TENANT_NAME | awk '{print $2;}')"
+crudini --set $core_cfg \
+        DEFAULT \
+        nova_admin_password \
+        "${NOVA_KEYSTONE_PASSWORD}"
+
+if [[ ${MECHANISM_DRIVERS} =~ linuxbridge ]]; then
+    crudini --set $ml2_cfg \
+        linux_bridge \
+        physical_interface_mappings \
+        "${NEUTRON_FLAT_NETWORK_NAME}:${NEUTRON_FLAT_NETWORK_INTERFACE}"
+fi
+
+su -s /bin/bash -c "neutron-db-manage --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugins/ml2/ml2_conf.ini upgrade head" neutron
+
+exec /usr/bin/neutron-server --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugins/ml2/ml2_conf.ini
diff --git a/docker/common/neutron/neutron-server/start.sh b/docker/common/neutron/neutron-server/start.sh
index fb971083f5..295caaac6b 100755
--- a/docker/common/neutron/neutron-server/start.sh
+++ b/docker/common/neutron/neutron-server/start.sh
@@ -1,98 +1,20 @@
 #!/bin/bash
+set -o errexit
 
-set -e
+CMD="/usr/bin/neutron-server"
+ARGS="--config-file /etc/neutron/plugins/ml2/ml2_conf.ini"
 
-. /opt/kolla/config-neutron.sh
+# Loading common functions.
+source /opt/kolla/kolla-common.sh
 
-: ${NEUTRON_FLAT_NETWORK_NAME:=physnet1}
-: ${NEUTRON_FLAT_NETWORK_INTERFACE:=eth1}
+# Config-internal script exec out of this function, it does not return here.
+set_configs
 
-check_required_vars KEYSTONE_ADMIN_TOKEN KEYSTONE_ADMIN_SERVICE_HOST \
-                    KEYSTONE_AUTH_PROTOCOL NOVA_API_SERVICE_HOST \
-                    NOVA_KEYSTONE_USER NOVA_KEYSTONE_PASSWORD \
-                    NEUTRON_DB_NAME NEUTRON_DB_USER NEUTRON_DB_PASSWORD \
-                    NEUTRON_KEYSTONE_USER NEUTRON_KEYSTONE_PASSWORD \
-                    ADMIN_TENANT_NAME NEUTRON_SERVER_SERVICE_HOST \
-                    PUBLIC_IP NEUTRON_DB_PASSWORD
-fail_unless_os_service_running keystone
-fail_unless_db
-
-mysql -h ${MARIADB_SERVICE_HOST} -u root -p${DB_ROOT_PASSWORD} mysql <<EOF
-CREATE DATABASE IF NOT EXISTS ${NEUTRON_DB_NAME} DEFAULT CHARACTER SET utf8;
-GRANT ALL PRIVILEGES ON ${NEUTRON_DB_NAME}.* TO
-       '${NEUTRON_DB_USER}'@'%' IDENTIFIED BY '${NEUTRON_DB_PASSWORD}'
-
-EOF
-
-export SERVICE_TOKEN="${KEYSTONE_ADMIN_TOKEN}"
-export SERVICE_ENDPOINT="${KEYSTONE_AUTH_PROTOCOL}://${KEYSTONE_ADMIN_SERVICE_HOST}:${KEYSTONE_ADMIN_SERVICE_PORT}/v2.0"
-
-# Configure Keystone Service Catalog
-crux user-create -n "${NEUTRON_KEYSTONE_USER}" \
-    -p "${NEUTRON_KEYSTONE_PASSWORD}" \
-    -t "${ADMIN_TENANT_NAME}" \
-    -r admin
-
-crux endpoint-create -n neutron -t network \
-    -I "${KEYSTONE_AUTH_PROTOCOL}://${NEUTRON_SERVER_SERVICE_HOST}:${NEUTRON_SERVER_SERVICE_PORT}" \
-    -P "${KEYSTONE_AUTH_PROTOCOL}://${NEUTRON_SERVER_SERVICE_HOST}:${NEUTRON_SERVER_SERVICE_PORT}" \
-    -A "${KEYSTONE_AUTH_PROTOCOL}://${NEUTRON_SERVER_SERVICE_HOST}:${NEUTRON_SERVER_SERVICE_PORT}"
-
-core_cfg=/etc/neutron/neutron.conf
-ml2_cfg=/etc/neutron/plugins/ml2/ml2_conf.ini
-
-# Logging
-crudini --set /etc/neutron/neutron.conf \
-        DEFAULT \
-        log_file \
-        "${NEUTRON_SERVER_LOG_FILE}"
-
-# Database
-crudini --set $core_cfg \
-        database \
-        connection \
-        "mysql://${NEUTRON_DB_USER}:${NEUTRON_DB_PASSWORD}@${MARIADB_SERVICE_HOST}/${NEUTRON_DB_NAME}"
-# Nova
-crudini --set $core_cfg \
-        DEFAULT \
-        notify_nova_on_port_status_changes \
-        "True"
-crudini --set $core_cfg \
-        DEFAULT \
-        notify_nova_on_port_data_changes \
-        "True"
-crudini --set $core_cfg \
-        DEFAULT \
-        nova_url \
-        "http://${NOVA_API_SERVICE_HOST}:${NOVA_API_SERVICE_PORT}/v2"
-crudini --set $core_cfg \
-        DEFAULT \
-        nova_admin_auth_url \
-        "${KEYSTONE_AUTH_PROTOCOL}://${KEYSTONE_ADMIN_SERVICE_HOST}:${KEYSTONE_ADMIN_SERVICE_PORT}/v2.0"
-crudini --set $core_cfg \
-        DEFAULT \
-        nova_region_name \
-        "${KEYSTONE_REGION}"
-crudini --set $core_cfg \
-        DEFAULT \
-        nova_admin_username \
-        "${NOVA_KEYSTONE_USER}"
-crudini --set $core_cfg \
-        DEFAULT \
-        nova_admin_tenant_id \
-        "$(keystone tenant-list | grep $ADMIN_TENANT_NAME | awk '{print $2;}')"
-crudini --set $core_cfg \
-        DEFAULT \
-        nova_admin_password \
-        "${NOVA_KEYSTONE_PASSWORD}"
-
-if [[ ${MECHANISM_DRIVERS} =~ linuxbridge ]]; then
-    crudini --set $ml2_cfg \
-        linux_bridge \
-        physical_interface_mappings \
-        "${NEUTRON_FLAT_NETWORK_NAME}:${NEUTRON_FLAT_NETWORK_INTERFACE}"
+# Bootstrap and exit if KOLLA_BOOTSTRAP variable is set. This catches all cases
+# of the KOLLA_BOOTSTRAP variable being set, including empty.
+if [[ "${!KOLLA_BOOTSTRAP[@]}" ]]; then
+    su -s /bin/bash -c "neutron-db-manage --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugins/ml2/ml2_conf.ini upgrade head" neutron
+    exit 0
 fi
 
-su -s /bin/bash -c "neutron-db-manage --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugins/ml2/ml2_conf.ini upgrade head" neutron
-
-exec /usr/bin/neutron-server --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugins/ml2/ml2_conf.ini
+exec $CMD $ARGS