#!/bin/bash
# Copyright (C) 2012
# Authors:
# Angus Salkeld
# Steven Dake
# ASL2.0

# sleep 1 = systemd's definition of start is different from mine

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 a Fedora 16/17 system"
    echo
    echo "start - Starts OpenStack"
    echo "stop - Stops OpenStack"
    echo "restart - Restart OpenStack"
    echo "install - Installs a fresh OpenStack system with Keystone from RPM repostories"
    echo "erase - permanently destroys an existing installation of OpenStack"
fi

OS_SERVICES=(qpidd mysqld openstack-keystone tgtd openstack-glance-api openstack-glance-registry openstack-nova-api openstack-nova-objectstore openstack-nova-compute openstack-nova-network openstack-nova-volume openstack-nova-scheduler openstack-nova-cert)

function os_status() {
    for service in ${OS_SERVICES[@]}
    do
        output=$(systemctl show "$service.service" --property=ActiveState)
        running=(${output//=/ }) #ActiveState=active
        echo "$service ${running[1]}" | awk '{ printf "%-40s %s\n", $1, $2}'
    done
}

OS_STATUS="OK"
function 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=$(systemctl show "$service.service" --property=ActiveState)
            running=${output#ActiveState=} #ActiveState=active
            if [[ ${running} != "active" ]]
            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
}


function os_start() {
    action=start
    sudo systemctl $action qpidd.service mysqld.service
    sleep 1
    sudo systemctl $action openstack-keystone.service tgtd.service
    sleep 1
    for svc in api registry
    do
        sudo systemctl $action openstack-glance-$svc.service
    done
    if ! sudo vgs | grep -q nova-volumes
    then
        sudo vgcreate nova-volumes $(sudo losetup --show -f /var/lib/nova/nova-volumes.img)
    fi

    for svc in api cert objectstore compute volume scheduler
    do
        sudo systemctl $action openstack-nova-$svc.service
    done

    # This must be started after openstack-nova-cert due to an SELinux
    # policy problem. See https://bugzilla.redhat.com/show_bug.cgi?id=857747
    sleep 2
    sudo systemctl $action openstack-nova-network.service
}

function os_stop() {
    action=stop
    sudo systemctl $action openstack-keystone.service tgtd.service
    for svc in api objectstore compute network volume scheduler cert
    do
        sudo systemctl $action openstack-nova-$svc.service
    done
    for svc in api registry
    do
        sudo systemctl $action openstack-glance-$svc.service
    done
}

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

function 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*
    sudo yum -q -y erase python-glance* python-nova* python-keystone* openstack-swift* openstack-dashboard

    sudo systemctl start mysqld.service
    sleep 1

    sudo openstack-db --service nova --drop $*
    sudo openstack-db --service glance --drop $*
    sudo openstack-db --service keystone --drop $*
    sudo yum -q -y erase openstack-utils

    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
}



function os_install() {
    sudo yum -q -y groupinstall Virtualization
    sudo yum -q -y install openstack-utils openstack-nova openstack-glance openstack-keystone openstack-dashboard scsi-target-utils qpid-cpp-server mysql-server qpid-cpp-server-daemon
    sudo dd if=/dev/zero of=/var/lib/nova/nova-volumes.img bs=1M seek=20k count=0
    sudo systemctl start mysqld.service
    sudo systemctl enable libvirtd.service
    sudo systemctl start libvirtd.service
    sleep 1
    # Configure the databases
    sudo openstack-db --service nova --init $*
    sudo openstack-db --service glance --init $*
    sudo openstack-db --service keystone --init $*

    # Create a keystone RC file
    mkdir -p $HOME/.openstack
    cat > $HOME/.openstack/keystonerc <<EOF
export ADMIN_TOKEN=$(openssl rand -hex 10)
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
EOF
    # Install keystone catalog
    source $HOME/.openstack/keystonerc
    sudo openstack-config --set /etc/keystone/keystone.conf DEFAULT admin_token $ADMIN_TOKEN
    sudo systemctl start openstack-keystone.service
    sleep 1

    sudo ADMIN_PASSWORD=$OS_PASSWORD SERVICE_PASSWORD=servicepass openstack-keystone-sample-data

    # Configure nova to use keystone
    sudo openstack-config --set /etc/nova/api-paste.ini filter:authtoken admin_tenant_name service
    sudo openstack-config --set /etc/nova/api-paste.ini filter:authtoken admin_user nova
    sudo openstack-config --set /etc/nova/api-paste.ini filter:authtoken admin_password servicepass
    sudo openstack-config --set /etc/nova/nova.conf DEFAULT auth_strategy keystone
    # Configure glance to use keystone
    sudo openstack-config --set /etc/glance/glance-api.conf paste_deploy flavor keystone
    sudo openstack-config --set /etc/glance/glance-registry.conf paste_deploy flavor keystone
    sudo openstack-config --set /etc/glance/glance-api-paste.ini filter:authtoken admin_tenant_name service
    sudo openstack-config --set /etc/glance/glance-api-paste.ini filter:authtoken admin_user glance
    sudo openstack-config --set /etc/glance/glance-api-paste.ini filter:authtoken admin_password servicepass
    sudo openstack-config --set /etc/glance/glance-registry-paste.ini filter:authtoken admin_tenant_name service
    sudo openstack-config --set /etc/glance/glance-registry-paste.ini filter:authtoken admin_user glance
    sudo openstack-config --set /etc/glance/glance-registry-paste.ini filter:authtoken admin_password servicepass

    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 demonet 10.0.0.0/24 1 256 --bridge=demonetbr0"
    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."

}

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

