#!/bin/bash
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (C) 2012, Red Hat, Inc.
# Steven Hardy <shardy@redhat.com>
# Based on tools/openstack
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

BASE_DIR=`dirname $0`
action=$1
if [ -z "$action" ]
then
    echo "openstack [start|stop|install|erase|status]"
    echo
    echo "This tool is designed to control OpenStack on an Ubuntu 12.XX system"
    echo "It installs a minimal openstack environment in order to demonstrate heat functionality"
    echo "Note swift and the horizon dashboard are not installed"
    echo
    echo "start - Starts OpenStack"
    echo "stop - Stops OpenStack"
    echo "restart - Restart OpenStack"
    echo "install - Installs a fresh OpenStack system with Keystone from repostories"
    echo "erase - permanently destroys an existing installation of OpenStack"
fi

BASE_SERVICES="tgt mysql"
OS_SERVICES="nova-compute nova-cert nova-vncproxy nova-objectstore keystone nova-api glance-registry nova-network nova-scheduler nova-volume glance-api keystone"

OS_REQ_PACKAGES="bridge-utils rabbitmq-server memcached python-memcache kvm libvirt-bin tgt open-iscsi open-iscsi-utils mysql-server python-mysqldb"
OS_GLANCE_PACKAGES="glance glance-api glance-client glance-common glance-registry python-glance"
OS_KEYSTONE_PACKAGES="keystone python-keystone python-keystoneclient"
OS_NOVA_PACKAGES="nova-api nova-cert nova-common nova-compute nova-compute-kvm nova-doc nova-network nova-objectstore nova-scheduler nova-vncproxy nova-volume python-nova python-novaclient"

INSTALL_CMD="sudo aptitude -y install"
UNINSTALL_CMD="sudo aptitude -y purge"

os_status () {
    for service in ${BASE_SERVICES}
    do
        output=$(initctl status ${service} | awk '{print $2}' | sed "s/,$//")
        echo "$service ${output}"  | awk '{ printf "%-40s %s\n", $1, $2}'
    done
    for service in ${OS_SERVICES}
    do
        output=$(initctl status ${service} | awk '{print $2}' | sed "s/,$//")
        echo "$service ${output}"  | awk '{ printf "%-40s %s\n", $1, $2}'
    done
}

OS_STATUS="OK"
os_check_status () {
    # If a service is not running, we try again up to MAX_TRIES times
    MAX_TRIES=5
    for service in ${OS_SERVICES}
    do
        attempts=0
        while [[ ${attempts} < ${MAX_TRIES} ]]
        do
            attempts=$((${attempts} + 1))
            output=$(initctl status $service)
            running=$(initctl status $service | cut -d"/" -f2 | sed "s/,.*$//")
            if [[ ${running} != "running" ]]
            then
                echo "Service ${service} does not seem to be running, waiting 1s ${attempts}/${MAX_TRIES}"
                OS_STATUS="FAIL ${service} : ${running}"
                sleep 1
            else
                echo "${service} ${running}" | awk '{ printf "%-40s %s\n", $1, $2}'
                OS_STATUS="OK"
                break
            fi
        done

        # If we get here and OS_STATUS != OK then we return as something failed
        if [[ ${OS_STATUS} != "OK" ]]
        then
            echo "Service ${service} has failed to start, check logs for errors"
            break
        fi
    done
}

DBPW=""
db_get_pw() {
    # If we're passed a -r rootpw argument, use it,
    # Otherwise, prompt for a password
    # Note we use the service name for the password, which is the default
    # behavior of the Fedora openstack-utils openstack-db script
    # Obviously this is only suitable for a development/demo installation
    if [ $# -eq 2 ]
    then
        if [ $1 = "-r" ]
        then
            DBPW=$2
        fi
    else
        echo "Enter mysql root password"
        read -s DBPW
    fi
}

db_setup () {
    db_get_pw $@
    for APP in nova glance keystone
    do
        MYSQL_APP_PW=${APP}
        echo "Creating '$APP' database." >&2
       mysql -u root --password=${DBPW} <<EOF
CREATE DATABASE $APP;
CREATE USER '$APP'@'localhost' IDENTIFIED BY '${MYSQL_APP_PW}';
CREATE USER '$APP'@'%' IDENTIFIED BY '${MYSQL_APP_PW}';
GRANT ALL ON $APP.* TO '$APP'@'localhost';
GRANT ALL ON $APP.* TO '$APP'@'%';
flush privileges;
EOF
    done
}

db_drop () {
    db_get_pw $@
    for APP in nova glance keystone
    do
        MYSQL_APP_PW=${APP}
        echo "Dropping '$APP' database." >&2
       mysql -u root --password=${DBPW} <<EOF
DROP USER '$APP'@'localhost';
DROP USER '$APP'@'%';
DROP DATABASE $APP;
flush privileges;
EOF
    done
}

os_start () {
    sudo rabbitmqctl start
    sleep 1
    if ! sudo vgs | grep -q nova-volumes
    then
        sudo vgcreate nova-volumes $(sudo losetup --show -f /var/lib/nova/nova-volumes.img)
    fi

    for service in ${BASE_SERVICES}
    do
        initctl start ${service}
    done
    for service in ${OS_SERVICES}
    do
        initctl start ${service}
    done
}

os_stop () {
    action=stop
    for service in ${OS_SERVICES}
    do
        echo "initctl stop ${service}"
        initctl stop ${service}
    done
}

os_restart () {
    action=restart
    os_stop
    sleep 1
    os_start
}

os_erase () {
    for net in `sudo nova-manage network list |
                awk '/^[[:digit:]]/ { print $9 }'`
    do
        sudo nova-manage network delete --uuid $net
    done

    os_stop
    sleep 1

    # Kill dnsmasq processes
    if find /var/lib/nova/networks -name '*.pid'; then
        sudo kill `cat /var/lib/nova/networks/*.pid`
    fi

    sudo rm -f /var/lib/libvirt/qemu/save/instance-000*
    sudo rm -f /var/lib/libvirt/qemu/instance-000*
    echo "$UNINSTALL_CMD $OS_GLANCE_PACKAGES" >&2
    $UNINSTALL_CMD $OS_GLANCE_PACKAGES
    echo "$UNINSTALL_CMD $OS_NOVA_PACKAGES" >&2
    $UNINSTALL_CMD $OS_NOVA_PACKAGES
    echo "$UNINSTALL_CMD $OS_KEYSTONE_PACKAGES" >&2
    $UNINSTALL_CMD $OS_KEYSTONE_PACKAGES

    db_drop $@

    sudo vgchange -an nova-volumes
    sudo losetup -d /dev/loop0
    sudo rm -f /var/lib/nova/nova-volumes.img
    sudo rm -rf /etc/{glance,nova,swift,keystone,openstack-dashboard} /var/lib/{glance,nova,swift,keystone} /var/log/{glance,nova,swift,keystone} /var/run/{glance,nova,swift,keystone}
    rm -f $HOME/.openstack/.keystonerc
}

get_id () {
    echo `$@ | awk '/ id / { print $4 }'`
}

os_install () {

    echo "Installing prerequisite packages" >&2
    ${INSTALL_CMD} ${OS_REQ_PACKAGES}
    echo "Installing Glance packages" >&2
    ${INSTALL_CMD} ${OS_GLANCE_PACKAGES}
    echo "Installing Keystone packages" >&2
    ${INSTALL_CMD} ${OS_KEYSTONE_PACKAGES}
    echo "Installing Nova packages" >&2
    ${INSTALL_CMD} ${OS_NOVA_PACKAGES}

    echo "Setting up /var/lib/nova/nova-volumes.img" >&2
    sudo dd if=/dev/zero of=/var/lib/nova/nova-volumes.img bs=1M seek=20k count=0
    # Configure the databases
    db_setup $*

    # Create a keystone RC file
    mkdir -p $HOME/.openstack
    TOKEN=$(openssl rand -hex 10)
    cat > $HOME/.openstack/keystonerc <<EOF
export ADMIN_TOKEN=$TOKEN
export OS_USERNAME=admin
export OS_PASSWORD=verybadpass
export OS_TENANT_NAME=admin
export OS_AUTH_URL=http://127.0.0.1:5000/v2.0/
export OS_AUTH_STRATEGY=keystone
export ADMIN_PASSWORD=$OS_PASSWORD
EOF
    # Configure keystone
    source $HOME/.openstack/keystonerc
    sudo cp /etc/keystone/keystone.conf /etc/keystone/keystone.conf.bak
    sudo -E sed -i "s/^admin_token = ADMIN/admin_token = $ADMIN_TOKEN/" /etc/keystone/keystone.conf
    sudo sed -i "s/^connection =.*$/connection = mysql:\/\/keystone:keystone@127.0.0.1\/keystone/" /etc/keystone/keystone.conf
    sudo sed -i "/^\[catalog\]/a template_file = /etc/keystone/default_catalog.templates" /etc/keystone/keystone.conf
    keystone-manage db_sync
    sudo initctl restart keystone
    sleep 5

    # Create keystone sample data (users/roles/tenants)
    ENABLE_ENDPOINTS=1 /usr/share/keystone/sample_data.sh

    # Configure nova to use keystone
    SERVICE_PASSWORD=$OS_PASSWORD
    sudo sed -i "s/^admin_tenant_name = %SERVICE_TENANT_NAME%/admin_tenant_name = service/" /etc/nova/api-paste.ini
    sudo sed -i "s/admin_user = %SERVICE_USER%/admin_user = nova/" /etc/nova/api-paste.ini
    sudo sed -i "s/admin_password = %SERVICE_PASSWORD%/admin_password = $SERVICE_PASSWORD/" /etc/nova/api-paste.ini
    sudo echo "--auth_strategy = keystone" >> /etc/nova/nova.conf
    sudo echo "--sql_connection=mysql://nova:nova@127.0.0.1/nova" >> /etc/nova/nova.conf
    nova-manage db sync

    # Configure glance to use keystone
    sudo sed -i "s/^admin_tenant_name = %SERVICE_TENANT_NAME%/admin_tenant_name = service/" /etc/glance/glance-api-paste.ini
    sudo sed -i "s/admin_user = %SERVICE_USER%/admin_user = glance/" /etc/glance/glance-api-paste.ini
    sudo sed -i "s/admin_password = %SERVICE_PASSWORD%/admin_password = $SERVICE_PASSWORD/" /etc/glance/glance-api-paste.ini
    sudo sed -i "s/^admin_tenant_name = %SERVICE_TENANT_NAME%/admin_tenant_name = service/" /etc/glance/glance-registry-paste.ini
    sudo sed -i "s/admin_user = %SERVICE_USER%/admin_user = glance/" /etc/glance/glance-registry-paste.ini
    sudo sed -i "s/admin_password = %SERVICE_PASSWORD%/admin_password = $SERVICE_PASSWORD/" /etc/glance/glance-registry-paste.ini
    sed -i "s/^sql_connection =.*$/sql_connection = mysql:\/\/glance:glance@127.0.0.1\/glance/" /etc/glance/glance-registry.conf
    cat >> /etc/glance/glance-registry.conf << EOF
[paste_deploy]
flavor = keystone
EOF
    cat >> /etc/glance/glance-api.conf << EOF
[paste_deploy]
flavor = keystone
EOF
    glance-manage version_control 0
    glance-manage db_sync

    # Restart all services and clear logfiles
    os_stop
    sleep 1
    sudo rm -rf /var/log/{glance,nova,swift,keystone}/*
    os_start
    sleep 1
    echo "Installation Complete."

    echo "Checking all expected services are running"
    os_check_status
    if [[ ${OS_STATUS} != "OK" ]]
    then
        echo "Service failed to start : ${OS_STATUS}, cannot continue"
        exit 1
    fi

    echo "Testing nova and glance.  If any errors are displayed, the install failed..."
    # Create additional flavors required by heat templates
    ${BASE_DIR}/nova_create_flavors.sh
    nova flavor-list
    glance index
    echo
    echo "note: This tool does not create a network.  Creating a network"
    echo "depends on your environment.  An example network create operation:"
    echo
    echo "  sudo nova-manage network create --label=demonet --fixed_range_v4=10.0.0.0/24 --bridge=demonetbr0 --bridge_interface=eth0"
    echo
    echo -e "The network range here should *not* be one used on your existing physical\n network."
    echo "It should be a range dedicated for the network that OpenStack will configure."
    echo "If 10.0.0.0/24 clashes with your local network, pick another range."
    echo "--bridge_interface argument should be a physical device to be bridged, eth0 in this example"
}

case $action in
    "")
        ;;
    start)
        os_start
        ;;
    stop)
        os_stop
        ;;
    restart)
        os_restart
        ;;
    erase)
        shift
        os_erase $*
        ;;
    install)
        shift
        os_install $*
        ;;
    status)
        os_status
        ;;
    *)
        echo "The action \"$action\" is not supported."
    ;;
esac
