# lib/barbican
# Install and start **Barbican** service

# To enable a minimal set of Barbican features, add the following to localrc:
#   enable_service barbican
#
# Dependencies:
# - functions
# - OS_AUTH_URL for auth in api
# - DEST set to the destination directory
# - SERVICE_PASSWORD, SERVICE_TENANT_NAME for auth in api
# - STACK_USER service user

# stack.sh
# ---------
# install_barbican
# configure_barbican
# init_barbican
# start_barbican
# stop_barbican
# cleanup_barbican

# Save trace setting
XTRACE=$(set +o | grep xtrace)
set +o xtrace


# Defaults
# --------

# Set up default directories
BARBICAN_DIR=$DEST/barbican
BARBICANCLIENT_DIR=$DEST/python-barbicanclient
BARBICAN_CONF_DIR=${BARBICAN_CONF_DIR:-/etc/barbican}
BARBICAN_CONF=$BARBICAN_CONF_DIR/barbican-api.conf
BARBICAN_PASTE_CONF=$BARBICAN_CONF_DIR/barbican-api-paste.ini
BARBICAN_API_LOG_DIR=$DEST/logs
BARBICAN_AUTH_CACHE_DIR=${BARBICAN_AUTH_CACHE_DIR:-/var/cache/barbican}

# Support potential entry-points console scripts
BARBICAN_BIN_DIR=$(get_python_exec_prefix)

# Set Barbican repository
BARBICAN_REPO=${BARBICAN_REPO:-${GIT_BASE}/openstack/barbican.git}
BARBICAN_BRANCH=${BARBICAN_BRANCH:-master}

# Set client library repository
BARBICANCLIENT_REPO=${BARBICANCLIENT_REPO:-${GIT_BASE}/openstack/python-barbicanclient.git}
BARBICANCLIENT_BRANCH=${BARBICANCLIENT_BRANCH:-master}

# Tell Tempest this project is present
TEMPEST_SERVICES+=,barbican


# Functions
# ---------

# cleanup_barbican - Remove residual data files, anything left over from previous
# runs that a clean run would need to clean up
function cleanup_barbican {
    :
}

# configure_barbicanclient - Set config files, create data dirs, etc
function configure_barbicanclient {
    setup_develop $BARBICANCLIENT_DIR
}

# configure_dogtag_plugin - Change config to use dogtag plugin
function configure_dogtag_plugin {
    sudo openssl pkcs12 -in /root/.dogtag/pki-tomcat/ca_admin_cert.p12 -passin pass:PASSWORD -out $BARBICAN_CONF_DIR/kra_admin_cert.pem -nodes
    sudo chown $USER $BARBICAN_CONF_DIR/kra_admin_cert.pem
    iniset $BARBICAN_CONF dogtag_plugin dogtag_port 8373
    iniset $BARBICAN_CONF secretstore enabled_secretstore_plugins dogtag_crypto
    iniset $BARBICAN_CONF certificate enabled_certificate_plugins dogtag
}

# configure_barbican - Set config files, create data dirs, etc
function configure_barbican {
    setup_develop $BARBICAN_DIR

    [ ! -d $BARBICAN_CONF_DIR ] && sudo mkdir -m 755 -p $BARBICAN_CONF_DIR
    sudo chown $USER $BARBICAN_CONF_DIR

    [ ! -d $BARBICAN_API_LOG_DIR ] &&  sudo mkdir -m 755 -p $BARBICAN_API_LOG_DIR
    sudo chown $USER $BARBICAN_API_LOG_DIR

    [ ! -d $BARBICAN_CONF_DIR ] && sudo mkdir -m 755 -p $BARBICAN_CONF_DIR
    sudo chown $USER $BARBICAN_CONF_DIR

    # Copy the barbican config files to the config dir
    cp $BARBICAN_DIR/etc/barbican/barbican-api.conf $BARBICAN_CONF_DIR
    cp $BARBICAN_DIR/etc/barbican/barbican-api-paste.ini $BARBICAN_CONF_DIR
    cp $BARBICAN_DIR/etc/barbican/barbican-admin-paste.ini $BARBICAN_CONF_DIR
    cp -R $BARBICAN_DIR/etc/barbican/vassals $BARBICAN_CONF_DIR

    # Copy functional test config
    cp $BARBICAN_DIR/etc/barbican/barbican-functional.conf $BARBICAN_CONF_DIR

    # Set the logging to INFO
    iniset $BARBICAN_CONF DEFAULT verbose True

    # Do not set to DEBUG
    iniset $BARBICAN_CONF DEFAULT debug False

    # Set the log file location
    iniset $BARBICAN_CONF DEFAULT log_file "$BARBICAN_API_LOG_DIR/barbican.log"

    # Format logging
    if [ "$LOG_COLOR" == "True" ] && [ "$SYSLOG" == "False" ]; then
        setup_colorized_logging $BARBICAN_CONF DEFAULT "project_id" "user_id"
    fi

    # Install the policy file for the API server
    cp $BARBICAN_DIR/etc/barbican/policy.json $BARBICAN_CONF_DIR
    iniset $BARBICAN_CONF DEFAULT policy_file $BARBICAN_CONF_DIR/policy.json

    # Set the database connection url
    iniset $BARBICAN_CONF DEFAULT sql_connection `database_connection_url barbican`

    # Increase default request buffer size, keystone auth PKI tokens can be very long
    iniset $BARBICAN_CONF_DIR/vassals/barbican-api.ini uwsgi buffer-size 65535

    # Rabbit settings
    if is_service_enabled rabbit; then
        iniset $BARBICAN_CONF 'secrets' broker rabbit://guest:$RABBIT_PASSWORD@$RABBIT_HOST
    else
        echo_summary "Barbican requires that the RabbitMQ service is enabled"
    fi

    ## Set up keystone

    # Turn on the middleware
    iniset $BARBICAN_PASTE_CONF 'pipeline:barbican_api' pipeline 'keystone_authtoken context apiapp'

    # Set the keystone parameters
    iniset $BARBICAN_PASTE_CONF 'filter:keystone_authtoken' auth_protocol $KEYSTONE_AUTH_PROTOCOL
    iniset $BARBICAN_PASTE_CONF 'filter:keystone_authtoken' auth_host $KEYSTONE_AUTH_HOST
    iniset $BARBICAN_PASTE_CONF 'filter:keystone_authtoken' auth_port $KEYSTONE_AUTH_PORT
    iniset $BARBICAN_PASTE_CONF 'filter:keystone_authtoken' admin_user barbican
    iniset $BARBICAN_PASTE_CONF 'filter:keystone_authtoken' admin_password $SERVICE_PASSWORD
    iniset $BARBICAN_PASTE_CONF 'filter:keystone_authtoken' admin_tenant_name $SERVICE_TENANT_NAME
    iniset $BARBICAN_PASTE_CONF 'filter:keystone_authtoken' signing_dir $BARBICAN_AUTH_CACHE_DIR
}

# init_barbican - Initialize etc.
function init_barbican {
    # Create cache dir
    sudo mkdir -p $BARBICAN_AUTH_CACHE_DIR
    sudo chown $STACK_USER $BARBICAN_AUTH_CACHE_DIR
    rm -f $BARBICAN_AUTH_CACHE_DIR/*

    recreate_database barbican utf8
}

# install_barbican - Collect source and prepare
function install_barbican {
    # Install package requirements
    if is_fedora; then
        install_package sqlite-devel openldap-devel
    fi
    # TODO(ravips): We need this until barbican gets into devstack
    ERROR_ON_CLONE=False
    git_clone $BARBICAN_REPO $BARBICAN_DIR $BARBICAN_BRANCH
    setup_develop $BARBICAN_DIR
    pip_install 'uwsgi'
}

# install_barbicanclient - Collect source and prepare
function install_barbicanclient {
    # TODO(ravips): We need this until barbican gets into devstack
    ERROR_ON_CLONE=False
    git_clone $BARBICANCLIENT_REPO $BARBICANCLIENT_DIR $BARBICANCLIENT_BRANCH
    setup_develop $BARBICANCLIENT_DIR
}

# start_barbican - Start running processes, including screen
function start_barbican {
    screen_it barbican "uwsgi --master --emperor $BARBICAN_CONF_DIR/vassals"
}

# stop_barbican - Stop running processes
function stop_barbican {
    # This will eventually be refactored to work like
    # Solum and Manila (script to kick off a wsgiref server)
    # For now, this will stop uWSGI rather than have it hang
    killall -9 uwsgi

    # This cleans up the PID file, but uses pkill so Barbican
    # uWSGI emperor process doesn't actually stop
    screen_stop barbican
}

function create_barbican_accounts {
    SERVICE_TENANT=$(keystone tenant-list | awk "/ $SERVICE_TENANT_NAME / { print \$2 }")
    ADMIN_ROLE=$(keystone role-list | awk "/ admin / { print \$2 }")

    BARBICAN_USER=$(keystone user-create --name=barbican \
                                                --pass="$SERVICE_PASSWORD" \
                                                --tenant-id $SERVICE_TENANT \
                                                --email=barbican@example.com \
                                                | grep " id " | get_field 2)
    keystone user-role-add --tenant-id $SERVICE_TENANT \
                            --user-id $BARBICAN_USER \
                            --role-id $ADMIN_ROLE
    if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
        BARBICAN_SERVICE=$(keystone service-create \
            --name=barbican \
            --type='key-manager' \
            --description="Barbican Service" \
            | grep " id " | get_field 2)
        keystone endpoint-create \
            --region RegionOne \
            --service_id $BARBICAN_SERVICE \
            --publicurl "http://$SERVICE_HOST:9311" \
            --adminurl "http://$SERVICE_HOST:9312" \
            --internalurl "http://$SERVICE_HOST:9311"
    fi

}

# Dogtag functions
# ----------------

function install_389_directory_server {
    # Make sure that 127.0.0.1 resolves to localhost.localdomain (fqdn)
    sudo sed -i 's/127.0.0.1[ \t]*localhost localhost.localdomain/127.0.0.1\tlocalhost.localdomain localhost/' /etc/hosts

    install_package 389-ds-base
    sudo mkdir -p /etc/389-ds

    # Instead of spawning a sub-shell to cat this whole chunk into the desired
    # file. I just cat it into a temporary file that this user will have access
    # to, and subsequently use elevated privileges to move the already made
    # file where we need it to be.
    cat > .tmp.setup.inf <<EOF
[General]
FullMachineName= localhost.localdomain
SuiteSpotUserID= nobody
SuiteSpotGroup= nobody

[slapd]
ServerPort= 389
ServerIdentifier= pki-tomcat
Suffix= dc=example,dc=com
RootDN= cn=Directory Manager
RootDNPwd= PASSWORD
EOF

    sudo mv .tmp.setup.inf /etc/389-ds/setup.inf

    sudo setup-ds.pl --silent --file=/etc/389-ds/setup.inf
}

function install_dogtag_ca {
    install_package pki-ca
    sudo mkdir -p /etc/dogtag

    cat > .tmp.ca.cfg <<EOF
[CA]
pki_admin_email=caadmin@example.com
pki_admin_name=caadmin
pki_admin_nickname=caadmin
pki_admin_password=PASSWORD
pki_admin_uid=caadmin
pki_backup_password=PASSWORD
pki_client_database_password=PASSWORD
pki_client_database_purge=False
pki_client_pkcs12_password=PASSWORD
pki_clone_pkcs12_password=PASSWORD
pki_ds_base_dn=dc=ca,dc=example,dc=com
pki_ds_database=ca
pki_ds_password=PASSWORD
pki_hostname=localhost
pki_security_domain_name=EXAMPLE
pki_token_password=PASSWORD
pki_https_port=8373
pki_http_port=8370
pki_ajp_port=8379
pki_tomcat_server_port=8375
EOF

    sudo mv .tmp.ca.cfg /etc/dogtag/ca.cfg

    sudo pkispawn -v -f /etc/dogtag/ca.cfg -s CA
}

function wait_for_ca {
    while true; do
        # If the sleep command is executed "as-is", the subprocess that it
        # executes will trigger the "exit_trap" and will cause this script to
        # fail. To avoid this, we run the sleep command inside this sub-shell,
        # so the signal will not be caught in this process.
        ca_running=$(sleep 2 && curl -s -k https://localhost:8373/ca/admin/ca/getStatus | grep -c running)
        if [[ $ca_running == 1 ]]; then
            break
        fi
    done
}

function install_dogtag_kra {
    install_package pki-kra
    sudo mkdir -p /etc/dogtag

    # Even though we are using localhost.localdomain, the server certificate by
    # default will get the real host name for the server. So we need to
    # properly configure the KRA to try to communicate with the real host name
    # instead of the localhost.
    cat > .tmp.kra.cfg <<EOF
[KRA]
pki_admin_cert_file=/root/.dogtag/pki-tomcat/ca_admin.cert
pki_admin_email=kraadmin@example.com
pki_admin_name=kraadmin
pki_admin_nickname=kraadmin
pki_admin_password=PASSWORD
pki_admin_uid=kraadmin
pki_backup_password=PASSWORD
pki_client_database_password=PASSWORD
pki_client_database_purge=False
pki_client_pkcs12_password=PASSWORD
pki_clone_pkcs12_password=PASSWORD
pki_ds_base_dn=dc=kra,dc=example,dc=com
pki_ds_database=kra
pki_ds_password=PASSWORD
pki_hostname=localhost
pki_security_domain_name=EXAMPLE
pki_security_domain_user=caadmin
pki_security_domain_password=PASSWORD
pki_token_password=PASSWORD
pki_https_port=8373
pki_http_port=8370
pki_ajp_port=8379
pki_tomcat_server_port=8375
pki_security_domain_hostname=localhost
pki_security_domain_https_port=8373
EOF

    sudo mv .tmp.kra.cfg /etc/dogtag/kra.cfg

    sudo pkispawn -v -f /etc/dogtag/kra.cfg -s KRA
}

function install_dogtag_plugin_dependencies {
    install_package nss-devel
    pip_install 'python-nss'
}

function install_dogtag_components {
    install_dogtag_plugin_dependencies
    install_389_directory_server
    install_dogtag_ca
    wait_for_ca
    install_dogtag_kra
}


# Restore xtrace
$XTRACE

# Local variables:
# mode: shell-script
# End:
