#!/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