#!/bin/bash

# COmanage Registry Dockerfile entrypoint
#
# Portions licensed to the University Corporation for Advanced Internet
# Development, Inc. ("UCAID") under one or more contributor license agreements.
# See the NOTICE file distributed with this work for additional information
# regarding copyright ownership.
#
# UCAID licenses this file to you 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.

if [ -n "$COMANAGE_DEBUG" ]
then
    OUTPUT=/dev/stdout
else
    OUTPUT=/dev/null
fi

# Configuration details that may be injected through environment
# variables or the contents of files.

injectable_config_vars=( 
    COMANAGE_REGISTRY_DATASOURCE
    COMANAGE_REGISTRY_DATABASE
    COMANAGE_REGISTRY_DATABASE_HOST
    COMANAGE_REGISTRY_DATABASE_USER
    COMANAGE_REGISTRY_DATABASE_USER_PASSWORD
    COMANAGE_REGISTRY_EMAIL_FROM
    COMANAGE_REGISTRY_EMAIL_TRANSPORT
    COMANAGE_REGISTRY_EMAIL_HOST
    COMANAGE_REGISTRY_EMAIL_PORT
    COMANAGE_REGISTRY_EMAIL_ACCOUNT
    COMANAGE_REGISTRY_EMAIL_ACCOUNT_PASSWORD
    COMANAGE_REGISTRY_SECURITY_SALT
    COMANAGE_REGISTRY_SECURITY_SEED
    ENV
    HTTPS_CERT_FILE
    HTTPS_PRIVKEY_FILE
    SERVER_NAME
    USERTOKEN
)

# If the file associated with a configuration variable is present then 
# read the value from it into the appropriate variable. So for example
# if the variable COMANAGE_REGISTRY_DATASOURCE_FILE exists and its
# value points to a file on the file system then read the contents
# of that file into the variable COMANAGE_REGISTRY_DATASOURCE.

for config_var in "${injectable_config_vars[@]}"
do
    eval file_name=\$"${config_var}_FILE";

    if [ -e "$file_name" ]; then
        declare "${config_var}"=`cat $file_name`
    fi
done

# Make sure the directory structure we need is available
# in the data volume for $COMANAGE_REGISTRY_DIR/local
mkdir -p "$COMANAGE_REGISTRY_DIR/local/Config"
mkdir -p "$COMANAGE_REGISTRY_DIR/local/Plugin"
mkdir -p "$COMANAGE_REGISTRY_DIR/local/View/Pages/public"
mkdir -p "$COMANAGE_REGISTRY_DIR/local/webroot/img"

# If the COmanage Registry database configuration file does not exist
# then try to create it from injected information with reasonable defaults
# that aid simple evaluation deployments.
if [ ! -e "$COMANAGE_REGISTRY_DIR/local/Config/database.php" ]; then
    cat > "$COMANAGE_REGISTRY_DIR/local/Config/database.php" <<EOF
<?php

class DATABASE_CONFIG {

  public \$default = array(
    'datasource' => '${COMANAGE_REGISTRY_DATASOURCE:-Database/Mysql}',
    'persistent' => false,
    'host' => '${COMANAGE_REGISTRY_DATABASE_HOST:-comanage-registry-database}',
    'login' => '${COMANAGE_REGISTRY_DATABASE_USER:-registry_user}',
    'password' => '${COMANAGE_REGISTRY_DATABASE_USER_PASSWORD:-password}',
    'database' => '${COMANAGE_REGISTRY_DATABASE:-registry}',
    'prefix' => 'cm_',
  );

}
EOF
fi

# If the COmanage Registry email configuration file does not exist
# then try to create it from injected information with reasonable defaults
# that aid simple evaluation deployments.
email_config="$COMANAGE_REGISTRY_DIR/local/Config/email.php"

if [ ! -e "$email_config" ]; then
    # If the deployer has injected an email for from then use it,
    # otherwise set a default purely as a template that can edited
    # easier later.
    if [ -n "$COMANAGE_REGISTRY_EMAIL_FROM" ]; then
        email_from="$COMANAGE_REGISTRY_EMAIL_FROM"
    else
        email_from="array('account@gmail.com' => 'Registry')"
    fi

    # If the injected email from does not include a single quote (')
    # then add them to make it a PHP string.
    if [[ ! $email_from =~ .*"'".* ]]; then
        email_from="'$email_from'"
    fi

    cat > "$email_config" <<EOF
<?php

class EmailConfig {

  public \$default = array(
    'from' => $email_from,
    'transport' => '${COMANAGE_REGISTRY_EMAIL_TRANSPORT:-Smtp}',
    'host' => '${COMANAGE_REGISTRY_EMAIL_HOST:-tls://smtp.gmail.com}',
    'port' => ${COMANAGE_REGISTRY_EMAIL_PORT:-465},
EOF

    # If the deployer has injected a username then add it to the configuration.
    if [ -n "$COMANAGE_REGISTRY_EMAIL_ACCOUNT" ]; then
       cat >> "$email_config" <<EOF
    'username' => '$COMANAGE_REGISTRY_EMAIL_ACCOUNT',
EOF
    fi

    # If the deployer has injected a password then add it to the configuration.
    if [ -n "$COMANAGE_REGISTRY_EMAIL_ACCOUNT_PASSWORD" ]; then
        cat >> "$email_config" <<EOF
    'password' => '$COMANAGE_REGISTRY_EMAIL_ACCOUNT_PASSWORD',
EOF
    fi

    # Complete the PHP array.
    cat >> "$email_config" <<EOF
  );
}
EOF

fi

# Loop until we are able to open a connection to the database.
DATABASE_TEST_SCRIPT="$COMANAGE_REGISTRY_DIR/app/Console/Command/DatabaseTestShell.php"

cat > $DATABASE_TEST_SCRIPT <<"EOF"
<?php

App::import('Model', 'ConnectionManager');

class DatabaseTestShell extends AppShell {
  function main() {
    try {
      $db = ConnectionManager::getDataSource('default');
    } catch (Exception $e) {
      $this->error("Unable to connect to datasource");
    }
    $this->out("Connected to datasource");
  }
}
EOF

pushd "$COMANAGE_REGISTRY_DIR/app" > "$OUTPUT" 2>&1

until ./Console/cake databaseTest > "$OUTPUT" 2>&1; do
    >&2 echo "Database is unavailable - sleeping"
    sleep 1
done

rm -f "$DATABASE_TEST_SCRIPT"

popd > "$OUTPUT" 2>&1

# We only want to run the setup script once since it creates
# state in the database. Until COmanage Registry has a better
# mechanism for telling us if setup has already been run
# we create an ephemeral CakePHP script to tell us.
SETUP_ALREADY_SCRIPT="$COMANAGE_REGISTRY_DIR/app/Console/Command/SetupAlreadyShell.php"

cat > $SETUP_ALREADY_SCRIPT <<"EOF"
<?php

class SetupAlreadyShell extends AppShell {
  var $uses = array('Co');

  function main() {
    $args = array();
    $args['conditions']['Co.name'] = 'COmanage';
    $args['contain'] = false;

    try {
      $co = $this->Co->find('first', $args);
    } catch (CakeException $e) {
      $this->out('Not setup already');
    }

    if(empty($co)) {
      $this->out('Not setup already');
    } else {
      $this->error('Setup already');
    }
  }
}
EOF

pushd "$COMANAGE_REGISTRY_DIR/app" > "$OUTPUT" 2>&1
./Console/cake setupAlready > "$OUTPUT" 2>&1
setup_already=$?

rm -f "$SETUP_ALREADY_SCRIPT"

if [ $setup_already -eq 0 ]; then
    rm -f "$COMANAGE_REGISTRY_DIR/local/Config/security.salt" > "$OUTPUT" 2>&1
    rm -f "$COMANAGE_REGISTRY_DIR/local/Config/security.seed" > "$OUTPUT" 2>&1
    # Run database twice until issue on develop branch is resolved. Since
    # the command is idempotent normally it is not a problem to have it run
    # more than once.
    ./Console/cake database > "$OUTPUT" 2>&1 && \
    ./Console/cake database > "$OUTPUT" 2>&1 && \
    ./Console/cake setup --admin-given-name "${COMANAGE_REGISTRY_ADMIN_GIVEN_NAME}" \
                         --admin-family-name "${COMANAGE_REGISTRY_ADMIN_FAMILY_NAME}" \
                         --admin-username "${COMANAGE_REGISTRY_ADMIN_USERNAME}" \
                         --enable-pooling "${COMANAGE_REGISTRY_ENABLE_POOLING}" > "$OUTPUT" 2>&1
    AUTO_GENERATED_SECURITY=1
fi

popd > "$OUTPUT" 2>&1

# If COmanage Registry CakePHP security salt and seed have been
# injected and the files do not otherwise exist create them.
if [[ -n "$COMANAGE_REGISTRY_SECURITY_SALT" && ( -n "$AUTO_GENERATED_SECURITY" || ! -e "$COMANAGE_REGISTRY_DIR/local/Config/security.salt" ) ]]; then
    echo "$COMANAGE_REGISTRY_SECURITY_SALT" > "$COMANAGE_REGISTRY_DIR/local/Config/security.salt"
fi

if [[ -n "$COMANAGE_REGISTRY_SECURITY_SEED" && ( -n "$AUTO_GENERATED_SECURITY" || ! -e "$COMANAGE_REGISTRY_DIR/local/Config/security.seed" ) ]]; then
    echo "$COMANAGE_REGISTRY_SECURITY_SEED" > "$COMANAGE_REGISTRY_DIR/local/Config/security.seed"
fi

# We always run upgradeVersion since it will not make any changes
# if the current and target versions are the same or if
# an upgrade from the current to the target version is not allowed.
pushd "$COMANAGE_REGISTRY_DIR/app" > "$OUTPUT" 2>&1

./Console/cake upgradeVersion "${COMANAGE_REGISTRY_UPGRADE_VERSION_OPTS}" > "$OUTPUT" 2>&1

popd > "$OUTPUT" 2>&1

# Force a datbase update if requested. This is helpful when deploying
# a new version of the code that does not result in a change in the
# version number and so upgradeVersion does not fire. An example
# of this scenario is when new code is introduced in the develop
# branch but before a release happens.
if [ -n "$COMANAGE_REGISTRY_DATABASE_SCHEMA_FORCE" ]; then
    echo "Forcing a database schema update..." > "$OUTPUT" 2>&1
    pushd "$COMANAGE_REGISTRY_DIR/app" > "$OUTPUT" 2>&1
    ./Console/cake database > "$OUTPUT" 2>&1
    popd > "$OUTPUT" 2>&1
fi

# Enable any supported non-core plugins if requested.
if [ -n "$COMANAGE_REGISTRY_ENABLE_PLUGIN" ]; then
    plugins=(`echo "$COMANAGE_REGISTRY_ENABLE_PLUGIN" | sed -e 's@,@ @'`) > "$OUTPUT" 2>&1
    for plugin in "${plugins[@]}"; 
    do 
        echo "Enabling available plugin $plugin..." > "$OUTPUT" 2>&1
        pushd "$COMANAGE_REGISTRY_DIR/local/Plugin" > "$OUTPUT" 2>&1
        ln -s "../../app/AvailablePlugin/$plugin" "$plugin" > "$OUTPUT" 2>&1
        popd > "$OUTPUT" 2>&1
        pushd "$COMANAGE_REGISTRY_DIR/app" > "$OUTPUT" 2>&1
        ./Console/cake database > "$OUTPUT" 2>&1
        popd > "$OUTPUT" 2>&1
    done
fi

# Remove any cache files generated thus far.
find "$COMANAGE_REGISTRY_DIR/app/tmp/cache" -type f -exec rm -f {} \;

# If defined use configured location of Apache HTTP Server 
# HTTPS certificate and key files. The certificate file may also
# include intermediate CA certificates, sorted from leaf to root.
if [ -n "$HTTPS_CERT_FILE" ]; then
    rm -f /etc/httpd/cert.pem
    cp "$HTTPS_CERT_FILE" /etc/httpd/cert.pem
    chown apache /etc/httpd/cert.pem
    chmod 0644 /etc/httpd/cert.pem
fi

if [ -n "$HTTPS_PRIVKEY_FILE" ]; then
    rm -f /etc/httpd/privkey.pem
    cp "$HTTPS_PRIVKEY_FILE" /etc/httpd/privkey.pem
    chown apache /etc/httpd/privkey.pem
    chmod 0600 /etc/httpd/privkey.pem
fi

# If SERVER_NAME has not been injected try to determine
# it from the HTTPS_CERT_FILE.
if [ -z "$SERVER_NAME" ]; then
    SERVER_NAME=`openssl x509 -in /etc/httpd/cert.pem -text -noout | sed -n '/X509v3 Subject Alternative Name:/ {n;p}' | sed -E 's/.*DNS:(.*)\s*$/\1/'`
    if [ -z "$SERVER_NAME" ]; then
        SERVER_NAME=`openssl x509 -in /etc/httpd/cert.pem -subject -noout | sed -E 's/subject=.*CN=(.*)\s*/\1/'`
    fi
fi

# Configure Apache HTTP Server with the server name.
sed -i -e s@%%SERVER_NAME%%@"${SERVER_NAME:-unknown}"@g /etc/httpd/conf.d/000-comanage.conf

# If ENV or USERTOKEN as injected by the deployer contain a semi-colon remove it.
if [[ $ENV =~ .*";".* ]]; then
    ENV=`echo $ENV | tr -d ';'`
    export ENV
fi

if [[ $USERTOKEN =~ .*";".* ]]; then
    USERTOKEN=`echo $USERTOKEN | tr -d ';'`
    export USERTOKEN
fi

# If ENV or USERTOKEN as injected by the deployer contain a space remove it.
if [[ $ENV =~ [[:space:]] ]]; then
    ENV=`echo $ENV | tr -d [:space:]`
    export ENV
fi

if [[ $USERTOKEN =~ [[:space:]] ]]; then
    USERTOKEN=`echo $USERTOKEN | tr -d [:space:]`
    export USERTOKEN
fi

# Create pipes to use for COmanage Registry instead of standard log files.
rm -f "$COMANAGE_REGISTRY_DIR/app/tmp/logs/error.log" > "$OUTPUT" 2>&1
rm -f "$COMANAGE_REGISTRY_DIR/app/tmp/logs/debug.log" > "$OUTPUT" 2>&1
mkfifo -m 666 "$COMANAGE_REGISTRY_DIR/app/tmp/logs/error.log" > "$OUTPUT" 2>&1
mkfifo -m 666 "$COMANAGE_REGISTRY_DIR/app/tmp/logs/debug.log" > "$OUTPUT" 2>&1

# Format any output from COmanange Registry into standard TIER form.
(cat <> "$COMANAGE_REGISTRY_DIR/app/tmp/logs/error.log" | awk -v ENV="$ENV" -v UT="$USERTOKEN" '{printf "comanage_registry;error.log;%s;%s;%s\n", ENV, UT, $0; fflush()}' 1>/tmp/logpipe)&
(cat <> "$COMANAGE_REGISTRY_DIR/app/tmp/logs/debug.log" | awk -v ENV="$ENV" -v UT="$USERTOKEN" '{printf "comanage_registry;debug.log;%s;%s;%s\n", ENV, UT, $0; fflush()}' 1>/tmp/logpipe)&

# Start Apache HTTP Server
exec /usr/sbin/httpd -DFOREGROUND