Merge "Setup user and endpoints for Savanna"
diff --git a/clean.sh b/clean.sh
index 395941a..480a812 100755
--- a/clean.sh
+++ b/clean.sh
@@ -15,6 +15,8 @@
 # Import common functions
 source $TOP_DIR/functions
 
+FILES=$TOP_DIR/files
+
 # Load local configuration
 source $TOP_DIR/stackrc
 
@@ -84,6 +86,10 @@
 cleanup_neutron
 cleanup_swift
 
+if is_service_enabled ldap; then
+    cleanup_ldap
+fi
+
 # Do the hypervisor cleanup until this can be moved back into lib/nova
 if [[ -r $NOVA_PLUGINS/hypervisor-$VIRT_DRIVER ]]; then
     cleanup_nova_hypervisor
diff --git a/files/apts/ldap b/files/apts/ldap
index 81a00f2..26f7aef 100644
--- a/files/apts/ldap
+++ b/files/apts/ldap
@@ -1,3 +1,3 @@
 ldap-utils
-slapd # NOPRIME
+slapd
 python-ldap
diff --git a/files/ldap/keystone.ldif.in b/files/ldap/keystone.ldif.in
new file mode 100644
index 0000000..cf51907
--- /dev/null
+++ b/files/ldap/keystone.ldif.in
@@ -0,0 +1,26 @@
+dn: ${BASE_DN}
+objectClass: dcObject
+objectClass: organizationalUnit
+dc: ${BASE_DC}
+ou: ${BASE_DC}
+
+dn: ou=UserGroups,${BASE_DN}
+objectClass: organizationalUnit
+ou: UserGroups
+
+dn: ou=Users,${BASE_DN}
+objectClass: organizationalUnit
+ou: Users
+
+dn: ou=Roles,${BASE_DN}
+objectClass: organizationalUnit
+ou: Roles
+
+dn: ou=Projects,${BASE_DN}
+objectClass: organizationalUnit
+ou: Projects
+
+dn: cn=9fe2ff9ee4384b1894a90878d3e92bab,ou=Roles,${BASE_DN}
+objectClass: organizationalRole
+ou: _member_
+cn: 9fe2ff9ee4384b1894a90878d3e92bab
diff --git a/files/ldap/manager.ldif.in b/files/ldap/manager.ldif.in
index e522150..de3b69d 100644
--- a/files/ldap/manager.ldif.in
+++ b/files/ldap/manager.ldif.in
@@ -1,10 +1,15 @@
 dn: olcDatabase={${LDAP_OLCDB_NUMBER}}hdb,cn=config
 changetype: modify
 replace: olcSuffix
-olcSuffix: dc=openstack,dc=org
+olcSuffix: ${BASE_DN}
 -
 replace: olcRootDN
-olcRootDN: dc=Manager,dc=openstack,dc=org
+olcRootDN: ${MANAGER_DN}
 -
 ${LDAP_ROOTPW_COMMAND}: olcRootPW
 olcRootPW: ${SLAPPASS}
+-
+replace: olcDbIndex
+olcDbIndex: objectClass eq
+olcDbIndex: default pres,eq
+olcDbIndex: cn,sn,givenName,co
diff --git a/files/ldap/openstack.ldif b/files/ldap/openstack.ldif
deleted file mode 100644
index 02caf3f..0000000
--- a/files/ldap/openstack.ldif
+++ /dev/null
@@ -1,26 +0,0 @@
-dn: dc=openstack,dc=org
-dc: openstack
-objectClass: dcObject
-objectClass: organizationalUnit
-ou: openstack
-
-dn: ou=UserGroups,dc=openstack,dc=org
-objectClass: organizationalUnit
-ou: UserGroups
-
-dn: ou=Users,dc=openstack,dc=org
-objectClass: organizationalUnit
-ou: Users
-
-dn: ou=Roles,dc=openstack,dc=org
-objectClass: organizationalUnit
-ou: Roles
-
-dn: ou=Projects,dc=openstack,dc=org
-objectClass: organizationalUnit
-ou: Projects
-
-dn: cn=9fe2ff9ee4384b1894a90878d3e92bab,ou=Roles,dc=openstack,dc=org
-objectClass: organizationalRole
-ou: _member_
-cn: 9fe2ff9ee4384b1894a90878d3e92bab
diff --git a/files/ldap/base-config.ldif b/files/ldap/suse-base-config.ldif.in
similarity index 77%
rename from files/ldap/base-config.ldif
rename to files/ldap/suse-base-config.ldif.in
index 026d8bc..00256ee 100644
--- a/files/ldap/base-config.ldif
+++ b/files/ldap/suse-base-config.ldif.in
@@ -12,8 +12,10 @@
 cn: schema
 
 include: file:///etc/openldap/schema/core.ldif
+include: file:///etc/openldap/schema/cosine.ldif
+include: file:///etc/openldap/schema/inetorgperson.ldif
 
 dn: olcDatabase={1}hdb,cn=config
 objectClass: olcHdbConfig
 olcDbDirectory: /var/lib/ldap
-olcSuffix: dc=openstack,dc=org
+olcSuffix: ${BASE_DN}
diff --git a/lib/keystone b/lib/keystone
index 6d0c1cd..712a509 100644
--- a/lib/keystone
+++ b/lib/keystone
@@ -151,17 +151,17 @@
 
     if is_service_enabled ldap; then
         #Set all needed ldap values
-        iniset $KEYSTONE_CONF ldap password  $LDAP_PASSWORD
-        iniset $KEYSTONE_CONF ldap user "dc=Manager,dc=openstack,dc=org"
-        iniset $KEYSTONE_CONF ldap suffix "dc=openstack,dc=org"
+        iniset $KEYSTONE_CONF ldap password $LDAP_PASSWORD
+        iniset $KEYSTONE_CONF ldap user $LDAP_MANAGER_DN
+        iniset $KEYSTONE_CONF ldap suffix $LDAP_BASE_DN
         iniset $KEYSTONE_CONF ldap use_dumb_member "True"
         iniset $KEYSTONE_CONF ldap user_attribute_ignore "enabled,email,tenants,default_project_id"
         iniset $KEYSTONE_CONF ldap tenant_attribute_ignore "enabled"
         iniset $KEYSTONE_CONF ldap tenant_domain_id_attribute "businessCategory"
         iniset $KEYSTONE_CONF ldap tenant_desc_attribute "description"
-        iniset $KEYSTONE_CONF ldap tenant_tree_dn "ou=Projects,dc=openstack,dc=org"
+        iniset $KEYSTONE_CONF ldap tenant_tree_dn "ou=Projects,$LDAP_BASE_DN"
         iniset $KEYSTONE_CONF ldap user_domain_id_attribute "businessCategory"
-        iniset $KEYSTONE_CONF ldap user_tree_dn "ou=Users,dc=openstack,dc=org"
+        iniset $KEYSTONE_CONF ldap user_tree_dn "ou=Users,$LDAP_BASE_DN"
         iniset $KEYSTONE_CONF DEFAULT member_role_id "9fe2ff9ee4384b1894a90878d3e92bab"
         iniset $KEYSTONE_CONF DEFAULT member_role_name "_member_"
     fi
@@ -337,6 +337,10 @@
 
 # init_keystone() - Initialize databases, etc.
 function init_keystone() {
+    if is_service_enabled ldap; then
+        init_ldap
+    fi
+
     # (Re)create keystone database
     recreate_database keystone utf8
 
diff --git a/lib/ldap b/lib/ldap
index 80992a7..e4bd416 100644
--- a/lib/ldap
+++ b/lib/ldap
@@ -9,68 +9,137 @@
 XTRACE=$(set +o | grep xtrace)
 set +o xtrace
 
+
+LDAP_DOMAIN=${LDAP_DOMAIN:-openstack.org}
+# Make an array of domain components
+DC=(${LDAP_DOMAIN/./ })
+
+# Leftmost domain component used in top-level entry
+LDAP_BASE_DC=${DC[0]}
+
+# Build the base DN
+dn=""
+for dc in ${DC[*]}; do
+    dn="$dn,dc=$dc"
+done
+LDAP_BASE_DN=${dn#,}
+
+LDAP_MANAGER_DN="${LDAP_MANAGER_DN:-cn=Manager,${LDAP_BASE_DN}}"
+LDAP_URL=${LDAP_URL:-ldap://localhost}
+
 LDAP_SERVICE_NAME=slapd
 
+if is_ubuntu; then
+    LDAP_OLCDB_NUMBER=1
+    LDAP_ROOTPW_COMMAND=replace
+elif is_fedora; then
+    LDAP_OLCDB_NUMBER=2
+    LDAP_ROOTPW_COMMAND=add
+elif is_suse; then
+    # SUSE has slappasswd in /usr/sbin/
+    PATH=$PATH:/usr/sbin/
+    LDAP_OLCDB_NUMBER=1
+    LDAP_ROOTPW_COMMAND=add
+    LDAP_SERVICE_NAME=ldap
+fi
+
+
 # Functions
 # ---------
 
+# Perform common variable substitutions on the data files
+# _ldap_varsubst file
+function _ldap_varsubst() {
+    local infile=$1
+    sed -e "
+        s|\${LDAP_OLCDB_NUMBER}|$LDAP_OLCDB_NUMBER|
+        s|\${SLAPPASS}|$SLAPPASS|
+        s|\${LDAP_ROOTPW_COMMAND}|$LDAP_ROOTPW_COMMAND|
+        s|\${BASE_DC}|$LDAP_BASE_DC|
+        s|\${BASE_DN}|$LDAP_BASE_DN|
+        s|\${MANAGER_DN}|$LDAP_MANAGER_DN|
+    " $infile
+}
+
+# clean_ldap() - Remove ldap server
+function cleanup_ldap() {
+    uninstall_package $(get_packages ldap)
+    if is_ubuntu; then
+        uninstall_package slapd ldap-utils libslp1
+        sudo rm -rf /etc/ldap/ldap.conf /var/lib/ldap
+    elif is_fedora; then
+        sudo rm -rf /etc/openldap /var/lib/ldap
+    elif is_suse; then
+        sudo rm -rf /var/lib/ldap
+    fi
+}
+
+# init_ldap
+# init_ldap() - Initialize databases, etc.
+function init_ldap() {
+    local keystone_ldif
+
+    TMP_LDAP_DIR=$(mktemp -d -t ldap.$$.XXXXXXXXXX)
+
+    # Remove data but not schemas
+    clear_ldap_state
+
+    # Add our top level ldap nodes
+    if ldapsearch -x -w $LDAP_PASSWORD -D "$LDAP_MANAGER_DN" -H $LDAP_URL -b "$LDAP_BASE_DN" | grep -q "Success"; then
+        printf "LDAP already configured for $LDAP_BASE_DC\n"
+    else
+        printf "Configuring LDAP for $LDAP_BASE_DC\n"
+        # If BASE_DN is changed, the user may override the default file
+        if [[ -r $FILES/ldap/${LDAP_BASE_DC}.ldif.in ]]; then
+            keystone_ldif=${LDAP_BASE_DC}.ldif
+        else
+            keystone_ldif=keystone.ldif
+        fi
+        _ldap_varsubst $FILES/ldap/${keystone_ldif}.in >$TMP_LDAP_DIR/${keystone_ldif}
+        if [[ -r $TMP_LDAP_DIR/${keystone_ldif} ]]; then
+            ldapadd -x -w $LDAP_PASSWORD -D "$LDAP_MANAGER_DN" -H $LDAP_URL -c -f $TMP_LDAP_DIR/${keystone_ldif}
+        fi
+    fi
+
+    rm -rf TMP_LDAP_DIR
+}
+
 # install_ldap
 # install_ldap() - Collect source and prepare
 function install_ldap() {
     echo "Installing LDAP inside function"
-    echo "LDAP_PASSWORD is $LDAP_PASSWORD"
     echo "os_VENDOR is $os_VENDOR"
-    printf "installing"
+
+    TMP_LDAP_DIR=$(mktemp -d -t ldap.$$.XXXXXXXXXX)
+
+    printf "installing OpenLDAP"
     if is_ubuntu; then
-        LDAP_OLCDB_NUMBER=1
-        LDAP_ROOTPW_COMMAND=replace
-        sudo DEBIAN_FRONTEND=noninteractive apt-get install slapd ldap-utils
-        #automatically starts LDAP on ubuntu so no need to call start_ldap
+        # Ubuntu automatically starts LDAP so no need to call start_ldap()
+        :
     elif is_fedora; then
-        LDAP_OLCDB_NUMBER=2
-        LDAP_ROOTPW_COMMAND=add
         start_ldap
     elif is_suse; then
-        LDAP_OLCDB_NUMBER=1
-        LDAP_ROOTPW_COMMAND=add
-        LDAP_SERVICE_NAME=ldap
-        # SUSE has slappasswd in /usr/sbin/
-        PATH=$PATH:/usr/sbin/
-        sudo slapadd -F /etc/openldap/slapd.d/ -bcn=config -l $FILES/ldap/base-config.ldif
+        _ldap_varsubst $FILES/ldap/suse-base-config.ldif.in >$TMP_LDAP_DIR/suse-base-config.ldif
+        sudo slapadd -F /etc/openldap/slapd.d/ -bcn=config -l $TMP_LDAP_DIR/suse-base-config.ldif
         sudo sed -i '/^OPENLDAP_START_LDAPI=/s/"no"/"yes"/g' /etc/sysconfig/openldap
         start_ldap
     fi
 
-    printf "generate password file"
-    SLAPPASS=`slappasswd -s $LDAP_PASSWORD`
+    echo "LDAP_PASSWORD is $LDAP_PASSWORD"
+    SLAPPASS=$(slappasswd -s $LDAP_PASSWORD)
+    printf "LDAP secret is $SLAPPASS\n"
 
-    printf "secret is $SLAPPASS\n"
-    #create manager.ldif
-    TMP_MGR_DIFF_FILE=`mktemp -t manager_ldiff.$$.XXXXXXXXXX.ldif`
-    sed -e "s|\${LDAP_OLCDB_NUMBER}|$LDAP_OLCDB_NUMBER|" -e "s|\${SLAPPASS}|$SLAPPASS|" -e "s|\${LDAP_ROOTPW_COMMAND}|$LDAP_ROOTPW_COMMAND|" $FILES/ldap/manager.ldif.in >> $TMP_MGR_DIFF_FILE
-
-    #update ldap olcdb
-    sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f $TMP_MGR_DIFF_FILE
+    # Create manager.ldif and add to olcdb
+    _ldap_varsubst $FILES/ldap/manager.ldif.in >$TMP_LDAP_DIR/manager.ldif
+    sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f $TMP_LDAP_DIR/manager.ldif
 
     # On fedora we need to manually add cosine and inetorgperson schemas
-    if is_fedora || is_suse; then
+    if is_fedora; then
         sudo ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/cosine.ldif
         sudo ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/inetorgperson.ldif
     fi
 
-    # add our top level ldap nodes
-    if ldapsearch -x -w $LDAP_PASSWORD -H ldap://localhost -D dc=Manager,dc=openstack,dc=org -x -b dc=openstack,dc=org | grep -q "Success"; then
-        printf "LDAP already configured for OpenStack\n"
-        if [[ "$KEYSTONE_CLEAR_LDAP" == "yes" ]]; then
-            # clear LDAP state
-            clear_ldap_state
-            # reconfigure LDAP for OpenStack
-            ldapadd -c -x -H ldap://localhost -D dc=Manager,dc=openstack,dc=org -w $LDAP_PASSWORD -f  $FILES/ldap/openstack.ldif
-        fi
-    else
-        printf "Configuring LDAP for OpenStack\n"
-        ldapadd -c -x -H ldap://localhost -D dc=Manager,dc=openstack,dc=org -w $LDAP_PASSWORD -f  $FILES/ldap/openstack.ldif
-    fi
+    rm -rf TMP_LDAP_DIR
 }
 
 # start_ldap() - Start LDAP
@@ -78,7 +147,6 @@
     sudo service $LDAP_SERVICE_NAME restart
 }
 
-
 # stop_ldap() - Stop LDAP
 function stop_ldap() {
     sudo service $LDAP_SERVICE_NAME stop
@@ -86,7 +154,7 @@
 
 # clear_ldap_state() - Clear LDAP State
 function clear_ldap_state() {
-    ldapdelete -x -w $LDAP_PASSWORD -H ldap://localhost -D dc=Manager,dc=openstack,dc=org -x -r "dc=openstack,dc=org"
+    ldapdelete -x -w $LDAP_PASSWORD -D "$LDAP_MANAGER_DN" -H $LDAP_URL -r "$LDAP_BASE_DN"
 }
 
 # Restore xtrace
diff --git a/lib/neutron b/lib/neutron
index 7376772..b05b16d 100644
--- a/lib/neutron
+++ b/lib/neutron
@@ -115,6 +115,13 @@
 # nova vif driver that all plugins should use
 NOVA_VIF_DRIVER=${NOVA_VIF_DRIVER:-"nova.virt.libvirt.vif.LibvirtGenericVIFDriver"}
 
+# The next two variables are configured by plugin
+# e.g.  _configure_neutron_l3_agent or lib/neutron_plugins/*
+#
+# The plugin supports L3.
+Q_L3_ENABLED=${Q_L3_ENABLED:-False}
+# L3 routers exist per tenant
+Q_L3_ROUTER_PER_TENANT=${Q_L3_ROUTER_PER_TENANT:-False}
 
 # List of config file names in addition to the main plugin config file
 # See _configure_neutron_common() for details about setting it up
diff --git a/lib/tempest b/lib/tempest
index 5a2c78d..5ee4e8a 100644
--- a/lib/tempest
+++ b/lib/tempest
@@ -15,6 +15,7 @@
 #   - ``PUBLIC_NETWORK_NAME``
 #   - ``Q_USE_NAMESPACE``
 #   - ``Q_ROUTER_NAME``
+#   - ``Q_L3_ENABLED``
 #   - ``VIRT_DRIVER``
 #   - ``LIBVIRT_TYPE``
 #   - ``KEYSTONE_SERVICE_PROTOCOL``, ``KEYSTONE_SERVICE_HOST`` from lib/keystone
@@ -202,7 +203,7 @@
 
     ssh_connect_method=${TEMPEST_SSH_CONNECT_METHOD:-$ssh_connect_method}
 
-    if is_service_enabled q-l3; then
+    if [ "$Q_L3_ENABLED" = "True" ]; then
         public_network_id=$(neutron net-list | grep $PUBLIC_NETWORK_NAME | \
             awk '{print $2}')
         if [ "$Q_USE_NAMESPACE" == "False" ]; then
diff --git a/lib/trove b/lib/trove
index 5ba4de5..6d5a56e 100644
--- a/lib/trove
+++ b/lib/trove
@@ -32,6 +32,17 @@
 TROVE_AUTH_CACHE_DIR=${TROVE_AUTH_CACHE_DIR:-/var/cache/trove}
 TROVE_BIN_DIR=/usr/local/bin
 
+# setup_trove_logging() - Adds logging configuration to conf files
+function setup_trove_logging() {
+    local CONF=$1
+    iniset $CONF DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL
+    iniset $CONF DEFAULT use_syslog $SYSLOG
+    if [ "$LOG_COLOR" == "True" ] && [ "$SYSLOG" == "False" ]; then
+        # Add color to logging output
+        setup_colorized_logging $CONF DEFAULT tenant user
+    fi
+}
+
 # create_trove_accounts() - Set up common required trove accounts
 
 # Tenant               User       Roles
@@ -121,6 +132,9 @@
     iniset $TROVE_LOCAL_CONF_DIR/trove-guestagent.conf.sample DEFAULT control_exchange trove
     sed -i "s/localhost/$NETWORK_GATEWAY/g" $TROVE_LOCAL_CONF_DIR/trove-guestagent.conf.sample
 
+    setup_trove_logging $TROVE_CONF_DIR/trove.conf
+    setup_trove_logging $TROVE_LOCAL_CONF_DIR/trove-guestagent.conf.sample
+
     # (Re)create trove taskmanager conf file if needed
     if is_service_enabled tr-tmgr; then
         TROVE_AUTH_ENDPOINT=$KEYSTONE_AUTH_PROTOCOL://$KEYSTONE_AUTH_HOST:$KEYSTONE_AUTH_PORT//v$IDENTITY_API_VERSION
@@ -132,6 +146,7 @@
         iniset $TROVE_CONF_DIR/trove-taskmanager.conf DEFAULT nova_proxy_admin_tenant_name trove
         iniset $TROVE_CONF_DIR/trove-taskmanager.conf DEFAULT nova_proxy_admin_pass $RADMIN_USER_PASS
         iniset $TROVE_CONF_DIR/trove-taskmanager.conf DEFAULT trove_auth_url $TROVE_AUTH_ENDPOINT
+        setup_trove_logging $TROVE_CONF_DIR/trove-taskmanager.conf
     fi
 
     # (Re)create trove conductor conf file if needed
@@ -143,6 +158,7 @@
         iniset $TROVE_CONF_DIR/trove-conductor.conf DEFAULT nova_proxy_admin_pass $RADMIN_USER_PASS
         iniset $TROVE_CONF_DIR/trove-conductor.conf DEFAULT trove_auth_url $TROVE_AUTH_ENDPOINT
         iniset $TROVE_CONF_DIR/trove-conductor.conf DEFAULT control_exchange trove
+        setup_trove_logging $TROVE_CONF_DIR/trove-conductor.conf
     fi
 }
 
diff --git a/tools/install_pip.sh b/tools/install_pip.sh
index 6b9b25e..a65a77e 100755
--- a/tools/install_pip.sh
+++ b/tools/install_pip.sh
@@ -67,7 +67,7 @@
             curl -O $PIP_GET_PIP_URL; \
         )
     fi
-    sudo python $FILES/get-pip.py
+    sudo -E python $FILES/get-pip.py
 }
 
 function install_pip_tarball() {
@@ -75,7 +75,7 @@
         curl -O $PIP_TAR_URL; \
         tar xvfz pip-$INSTALL_PIP_VERSION.tar.gz 1>/dev/null; \
         cd pip-$INSTALL_PIP_VERSION; \
-        sudo python setup.py install 1>/dev/null; \
+        sudo -E python setup.py install 1>/dev/null; \
     )
 }
 
diff --git a/tools/xen/build_xva.sh b/tools/xen/build_xva.sh
index 7272fe2..958102b 100755
--- a/tools/xen/build_xva.sh
+++ b/tools/xen/build_xva.sh
@@ -119,6 +119,20 @@
     if su -c "/opt/stack/run.sh" $STACK_USER; then
         touch /var/run/devstack.succeeded
     fi
+
+    # Update /etc/issue
+    {
+        echo "OpenStack VM - Installed by DevStack"
+        IPADDR=\$(ip -4 address show eth0 | sed -n 's/.*inet \\([0-9\.]\\+\\).*/\1/p')
+        echo "  Management IP:   \$IPADDR"
+        echo -n "  Devstack run:    "
+        if [ -e /var/run/devstack.succeeded ]; then
+            echo "SUCCEEDED"
+        else
+            echo "FAILED"
+        fi
+        echo ""
+    } > /etc/issue
     initctl start hvc0 > /dev/null 2>&1
 end script
 EOF