Merge "Add network block device package to support LXC rootfs mount on it."
diff --git a/functions b/functions
index edc4bf9..445af5f 100644
--- a/functions
+++ b/functions
@@ -408,6 +408,9 @@
         else
             DISTRO="sle${os_RELEASE}sp${os_UPDATE}"
         fi
+    elif [[ "$os_VENDOR" =~ (Red Hat) || "$os_VENDOR" =~ (CentOS) ]]; then
+        # Drop the . release as we assume it's compatible
+        DISTRO="rhel${os_RELEASE::1}"
     else
         # Catch-all for now is Vendor + Release + Update
         DISTRO="$os_VENDOR-$os_RELEASE.$os_UPDATE"
@@ -440,7 +443,6 @@
     [ "$os_VENDOR" = "Fedora" ] || [ "$os_VENDOR" = "Red Hat" ] || [ "$os_VENDOR" = "CentOS" ]
 }
 
-
 # Determine if current distribution is a SUSE-based distribution
 # (openSUSE, SLE).
 # is_suse
diff --git a/lib/baremetal b/lib/baremetal
index 24cce9f..17a967f 100644
--- a/lib/baremetal
+++ b/lib/baremetal
@@ -427,7 +427,7 @@
        "$mac_1" \
        | grep ' id ' | get_field 2 )
     [ $? -eq 0 ] || [ "$id" ] || die "Error adding baremetal node"
-    id2=$(nova baremetal-add-interface "$id" "$mac_2" )
+    id2=$(nova baremetal-interface-add "$id" "$mac_2" )
     [ $? -eq 0 ] || [ "$id2" ] || die "Error adding interface to barmetal node $id"
 }
 
diff --git a/lib/ceilometer b/lib/ceilometer
index 58cafd1..f7d14d5 100644
--- a/lib/ceilometer
+++ b/lib/ceilometer
@@ -68,7 +68,6 @@
 
     iniset $CEILOMETER_CONF DEFAULT notification_topics 'notifications,glance_notifications'
     iniset $CEILOMETER_CONF DEFAULT verbose True
-    iniset $CEILOMETER_CONF DEFAULT `database_connection_url nova`
 
     # Install the policy file for the API server
     cp $CEILOMETER_DIR/etc/ceilometer/policy.json $CEILOMETER_CONF_DIR
diff --git a/lib/quantum b/lib/quantum
index 68c0539..e2a0d53 100644
--- a/lib/quantum
+++ b/lib/quantum
@@ -92,6 +92,9 @@
 Q_USE_DEBUG_COMMAND=${Q_USE_DEBUG_COMMAND:-False}
 # The name of the default q-l3 router
 Q_ROUTER_NAME=${Q_ROUTER_NAME:-router1}
+# List of config file names in addition to the main plugin config file
+# See _configure_quantum_common() for details about setting it up
+declare -a Q_PLUGIN_EXTRA_CONF_FILES
 
 if is_service_enabled quantum; then
     Q_RR_CONF_FILE=$QUANTUM_CONF_DIR/rootwrap.conf
@@ -358,8 +361,14 @@
 
 # Start running processes, including screen
 function start_quantum_service_and_check() {
+    # build config-file options
+    local cfg_file
+    local CFG_FILE_OPTIONS="--config-file $QUANTUM_CONF --config-file /$Q_PLUGIN_CONF_FILE"
+    for cfg_file in ${Q_PLUGIN_EXTRA_CONF_FILES[@]}; do
+         CFG_FILE_OPTIONS+=" --config-file /$cfg_file"
+    done
     # Start the Quantum service
-    screen_it q-svc "cd $QUANTUM_DIR && python $QUANTUM_DIR/bin/quantum-server --config-file $QUANTUM_CONF --config-file /$Q_PLUGIN_CONF_FILE"
+    screen_it q-svc "cd $QUANTUM_DIR && python $QUANTUM_DIR/bin/quantum-server $CFG_FILE_OPTIONS"
     echo "Waiting for Quantum to start..."
     if ! timeout $SERVICE_TIMEOUT sh -c "while ! http_proxy= wget -q -O- http://$Q_HOST:$Q_PORT; do sleep 1; done"; then
       die $LINENO "Quantum did not start"
@@ -405,8 +414,11 @@
 
     cp $QUANTUM_DIR/etc/quantum.conf $QUANTUM_CONF
 
-    # set plugin-specific variables
-    # Q_PLUGIN_CONF_PATH, Q_PLUGIN_CONF_FILENAME, Q_DB_NAME, Q_PLUGIN_CLASS
+    # Set plugin-specific variables Q_DB_NAME, Q_PLUGIN_CLASS.
+    # For main plugin config file, set Q_PLUGIN_CONF_PATH, Q_PLUGIN_CONF_FILENAME.
+    # For addition plugin config files, set Q_PLUGIN_EXTRA_CONF_PATH,
+    # Q_PLUGIN_EXTRA_CONF_FILES.  For example:
+    #    Q_PLUGIN_EXTRA_CONF_FILES=(file1, file2)
     quantum_plugin_configure_common
 
     if [[ $Q_PLUGIN_CONF_PATH == '' || $Q_PLUGIN_CONF_FILENAME == '' || $Q_PLUGIN_CLASS == '' ]]; then
@@ -421,6 +433,22 @@
     iniset /$Q_PLUGIN_CONF_FILE DATABASE sql_connection `database_connection_url $Q_DB_NAME`
     iniset $QUANTUM_CONF DEFAULT state_path $DATA_DIR/quantum
 
+    # If addition config files are set, make sure their path name is set as well
+    if [[ ${#Q_PLUGIN_EXTRA_CONF_FILES[@]} > 0 && $Q_PLUGIN_EXTRA_CONF_PATH == '' ]]; then
+        die $LINENO "Quantum additional plugin config not set.. exiting"
+    fi
+
+    # If additional config files exist, copy them over to quantum configuration
+    # directory
+    if [[ $Q_PLUGIN_EXTRA_CONF_PATH != '' ]]; then
+        mkdir -p /$Q_PLUGIN_EXTRA_CONF_PATH
+        local f
+        for (( f=0; $f < ${#Q_PLUGIN_EXTRA_CONF_FILES[@]}; f+=1 )); do
+            Q_PLUGIN_EXTRA_CONF_FILES[$f]=$Q_PLUGIN_EXTRA_CONF_PATH/${Q_PLUGIN_EXTRA_CONF_FILES[$f]}
+            cp $QUANTUM_DIR/${Q_PLUGIN_EXTRA_CONF_FILES[$f]} /${Q_PLUGIN_EXTRA_CONF_FILES[$f]}
+        done
+    fi
+
     _quantum_setup_rootwrap
 }
 
diff --git a/tools/xen/functions b/tools/xen/functions
index 5b4a661..a7d7798 100644
--- a/tools/xen/functions
+++ b/tools/xen/functions
@@ -1,10 +1,8 @@
 #!/bin/bash
 
 function xapi_plugin_location {
-    for PLUGIN_DIR in "/etc/xapi.d/plugins/" "/usr/lib/xcp/plugins/"
-    do
-        if [ -d $PLUGIN_DIR ]
-        then
+    for PLUGIN_DIR in "/etc/xapi.d/plugins/" "/usr/lib/xcp/plugins/"; do
+        if [ -d $PLUGIN_DIR ]; then
             echo $PLUGIN_DIR
             return 0
         fi
@@ -17,7 +15,13 @@
 }
 
 function create_directory_for_kernels {
-    mkdir -p "/boot/guest"
+    if [ -d "/boot/guest" ]; then
+        echo "INFO: /boot/guest directory already exists, using that" >&2
+    else
+        local LOCALPATH="$(get_local_sr_path)/os-guest-kernels"
+        mkdir -p $LOCALPATH
+        ln -s $LOCALPATH /boot/guest
+    fi
 }
 
 function extract_remote_zipball {
@@ -53,3 +57,11 @@
     rm -rf $EXTRACTED_FILES
     chmod a+x ${XAPI_PLUGIN_DIR}*
 }
+
+function get_local_sr {
+    xe sr-list name-label="Local storage" --minimal
+}
+
+function get_local_sr_path {
+    echo "/var/run/sr-mount/$(get_local_sr)"
+}
diff --git a/tools/xen/mocks b/tools/xen/mocks
index b006558..6da6acb 100644
--- a/tools/xen/mocks
+++ b/tools/xen/mocks
@@ -12,6 +12,18 @@
     exit 1
 }
 
+test ! -e "$XE_RESPONSE" && {
+    echo "Mocking is not set up properly."
+    echo "XE_RESPONSE should point to an existing file."
+    exit 1
+}
+
+test ! -e "$XE_CALLS" && {
+    echo "Mocking is not set up properly."
+    echo "XE_CALLS should point to an existing file."
+    exit 1
+}
+
 function mktemp {
     if test "${1:-}" = "-d";
     then
@@ -41,6 +53,10 @@
     echo "rm $@" >> $LIST_OF_ACTIONS
 }
 
+function ln {
+    echo "ln $@" >> $LIST_OF_ACTIONS
+}
+
 function [ {
     if test "${1:-}" = "-d";
     then
@@ -57,3 +73,13 @@
     echo "Mock test does not implement the requested function"
     exit 1
 }
+
+function xe {
+    cat $XE_RESPONSE
+    {
+    for i in $(seq "$#")
+    do
+        eval "echo \"\$$i\""
+    done
+    } >> $XE_CALLS
+}
diff --git a/tools/xen/test_functions.sh b/tools/xen/test_functions.sh
index 6817ec3..62393ca 100755
--- a/tools/xen/test_functions.sh
+++ b/tools/xen/test_functions.sh
@@ -23,15 +23,27 @@
 
     LIST_OF_ACTIONS=$(mktemp)
     truncate -s 0 $LIST_OF_ACTIONS
+
+    XE_RESPONSE=$(mktemp)
+    truncate -s 0 $XE_RESPONSE
+
+    XE_CALLS=$(mktemp)
+    truncate -s 0 $XE_CALLS
 }
 
 # Teardown
 function after_each_test {
     rm -f $LIST_OF_DIRECTORIES
     rm -f $LIST_OF_ACTIONS
+    rm -f $XE_RESPONSE
+    rm -f $XE_CALLS
 }
 
 # Helpers
+function setup_xe_response {
+    echo "$1" > $XE_RESPONSE
+}
+
 function given_directory_exists {
     echo "$1" >> $LIST_OF_DIRECTORIES
 }
@@ -44,6 +56,30 @@
     [ "$?" != "0" ] || exit 1
 }
 
+function assert_xe_min {
+    grep -qe "^--minimal\$" $XE_CALLS
+}
+
+function assert_xe_param {
+    grep -qe "^$1\$" $XE_CALLS
+}
+
+function mock_out {
+    local FNNAME="$1"
+    local OUTPUT="$2"
+
+    . <(cat << EOF
+function $FNNAME {
+    echo "$OUTPUT"
+}
+EOF
+)
+}
+
+function assert_symlink {
+    grep -qe "^ln -s $2 $1\$" $LIST_OF_ACTIONS
+}
+
 # Tests
 function test_plugin_directory_on_xenserver {
     given_directory_exists "/etc/xapi.d/plugins/"
@@ -80,9 +116,26 @@
 }
 
 function test_create_directory_for_kernels {
-    (. mocks && create_directory_for_kernels)
+    (
+        . mocks
+        mock_out get_local_sr uuid1
+        create_directory_for_kernels
+    )
 
-    assert_directory_exists "/boot/guest"
+    assert_directory_exists "/var/run/sr-mount/uuid1/os-guest-kernels"
+    assert_symlink "/boot/guest" "/var/run/sr-mount/uuid1/os-guest-kernels"
+}
+
+function test_create_directory_for_kernels_existing_dir {
+    (
+        . mocks
+        given_directory_exists "/boot/guest"
+        create_directory_for_kernels
+    )
+
+    diff -u $LIST_OF_ACTIONS - << EOF
+[ -d /boot/guest ]
+EOF
 }
 
 function test_extract_remote_zipball {
@@ -107,6 +160,23 @@
     rm -rf $tmpdir
 }
 
+function test_get_local_sr {
+    setup_xe_response "uuid123"
+
+    local RESULT=$(. mocks && get_local_sr)
+
+    [ "$RESULT" == "uuid123" ]
+
+    assert_xe_min
+    assert_xe_param "sr-list" "name-label=Local storage"
+}
+
+function test_get_local_sr_path {
+    local RESULT=$(mock_out get_local_sr "uuid1" && get_local_sr_path)
+
+    [ "/var/run/sr-mount/uuid1" == "$RESULT" ]
+}
+
 # Test runner
 [ "$1" = "" ] && {
     grep -e "^function *test_" $0 | cut -d" " -f2