che-server/dockerfiles/che/entrypoint.sh

369 lines
12 KiB
Bash
Executable File

#!/bin/bash
#
# Copyright (c) 2012-2017 Red Hat, Inc.
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v1.0
# which accompanies this distribution, and is available at
# http://www.eclipse.org/legal/epl-v10.html
#
# Contributors:
# Red Hat, Inc.- initial API and implementation
#
init_global_variables () {
# For coloring console output
BLUE='\033[1;34m'
GREEN='\033[0;32m'
NC='\033[0m'
USAGE="
Usage:
che [COMMAND]
start Starts server with output in the background
stop Stops ${CHE_MINI_PRODUCT_NAME} server
run Starts server with output in the foreground
Variables:
CHE_SERVER_ACTION Another way to set the [COMMAND] to [run | start | stop]
CHE_PORT The port the Che server will listen on
CHE_IP The IP address of the host - must be set if remote clients connecting
CHE_BLOCKING_ENTROPY Starts Tomcat with blocking entropy: -Djava.security.egd=file:/dev/./urandom
CHE_LAUNCH_DOCKER_REGISTRY If true, uses Docker registry to save ws snapshots instead of disk
CHE_REGISTRY_HOST Hostname of Docker registry to launch, otherwise 'localhost'
CHE_LOG_LEVEL [INFO | DEBUG] Sets the output level of Tomcat messages
CHE_DEBUG_SERVER If true, activates Tomcat's JPDA debugging mode
CHE_HOME Where the Che assembly resides - self-determining if not set
"
# Use blocking entropy -- needed for some servers
DEFAULT_CHE_BLOCKING_ENTROPY=false
CHE_BLOCKING_ENTROPY=${CHE_BLOCKING_ENTROPY:-${DEFAULT_CHE_BLOCKING_ENTROPY}}
DEFAULT_CHE_SERVER_ACTION=run
CHE_SERVER_ACTION=${CHE_SERVER_ACTION:-${DEFAULT_CHE_SERVER_ACTION}}
DEFAULT_CHE_LAUNCH_DOCKER_REGISTRY=false
CHE_LAUNCH_DOCKER_REGISTRY=${CHE_LAUNCH_DOCKER_REGISTRY:-${DEFAULT_CHE_LAUNCH_DOCKER_REGISTRY}}
# Must be exported as this will be needed by Tomcat's JVM
DEFAULT_CHE_REGISTRY_HOST=localhost
export CHE_REGISTRY_HOST=${CHE_REGISTRY_HOST:-${DEFAULT_CHE_REGISTRY_HOST}}
DEFAULT_CHE_PORT=8080
export CHE_PORT=${CHE_PORT:-${DEFAULT_CHE_PORT}}
DEFAULT_CHE_IP=
CHE_IP=${CHE_IP:-${DEFAULT_CHE_IP}}
DEFAULT_CHE_LOG_LEVEL=INFO
CHE_LOG_LEVEL=${CHE_LOG_LEVEL:-${DEFAULT_CHE_LOG_LEVEL}}
DEFAULT_CHE_LOGS_DIR="${CATALINA_HOME}/logs/"
export CHE_LOGS_DIR=${CHE_LOGS_DIR:-${DEFAULT_CHE_LOGS_DIR}}
DEFAULT_CHE_DEBUG_SERVER=false
CHE_DEBUG_SERVER=${CHE_DEBUG_SERVER:-${DEFAULT_CHE_DEBUG_SERVER}}
}
error () {
echo
echo "!!!"
echo -e "!!! ${1}"
echo "!!!"
return 0
}
usage () {
echo "${USAGE}"
}
set_environment_variables () {
### Set value of derived environment variables.
# CHE_DOCKER_IP is used internally by Che to set its IP address
if [[ -z "${CHE_DOCKER_IP}" ]]; then
if [[ -n "${CHE_IP}" ]]; then
export CHE_DOCKER_IP="${CHE_IP}"
fi
fi
# Convert Tomcat environment variables to POSIX format.
if [[ "${JAVA_HOME}" == *":"* ]]; then
JAVA_HOME=$(echo /"${JAVA_HOME}" | sed 's|\\|/|g' | sed 's|:||g')
fi
# Convert Che environment variables to POSIX format.
if [[ "${CHE_HOME}" == *":"* ]]; then
CHE_HOME=$(echo /"${CHE_HOME}" | sed 's|\\|/|g' | sed 's|:||g')
fi
# Sets the location of the application server and its executables
# Internal property - should generally not be overridden
export CATALINA_HOME="${CHE_HOME}/tomcat"
# Convert windows path name to POSIX
if [[ "${CATALINA_HOME}" == *":"* ]]; then
CATALINA_HOME=$(echo /"${CATALINA_HOME}" | sed 's|\\|/|g' | sed 's|:||g')
fi
# Internal properties - should generally not be overridden
export CATALINA_BASE="${CHE_HOME}/tomcat"
export ASSEMBLY_BIN_DIR="${CATALINA_HOME}/bin"
export CHE_LOGS_LEVEL="${CHE_LOG_LEVEL}"
}
docker_exec() {
"$(which docker)" "$@"
}
start_che_server () {
if ${CHE_LAUNCH_DOCKER_REGISTRY} ; then
# Export the value of host here
launch_docker_registry
fi
#########################################
# Launch Che natively as a tomcat server
call_catalina
}
stop_che_server () {
CHE_SERVER_ACTION="stop"
echo -e "Stopping Che server running on localhost:${CHE_PORT}"
call_catalina >/dev/null 2>&1
}
call_catalina () {
# Test to see that Che application server is where we expect it to be
if [ ! -d "${ASSEMBLY_BIN_DIR}" ]; then
error "Could not find Che's application server."
return 1;
fi
### Initialize default JVM arguments to run che
if [[ "${CHE_BLOCKING_ENTROPY}" == true ]]; then
[ -z "${JAVA_OPTS}" ] && JAVA_OPTS="-Xms256m -Xmx1024m"
else
[ -z "${JAVA_OPTS}" ] && JAVA_OPTS="-Xms256m -Xmx1024m -Djava.security.egd=file:/dev/./urandom"
fi
### Cannot add this in setenv.sh.
### We do the port mapping here, and this gets inserted into server.xml when tomcat boots
export JAVA_OPTS="${JAVA_OPTS} -Dport.http=${CHE_PORT} -Dche.home=${CHE_HOME}"
export SERVER_PORT=${CHE_PORT}
# Launch the Che application server, passing in command line parameters
if [[ "${CHE_DEBUG_SERVER}" == true ]]; then
"${ASSEMBLY_BIN_DIR}"/catalina.sh jpda ${CHE_SERVER_ACTION}
else
"${ASSEMBLY_BIN_DIR}"/catalina.sh ${CHE_SERVER_ACTION}
fi
}
kill_and_launch_docker_registry () {
echo -e "Launching Docker container named ${GREEN}registry${NC} from image ${GREEN}registry:2${NC}."
docker_exec rm -f registry &> /dev/null || true
docker_exec run -d -p 5000:5000 --restart=always --name registry registry:2
}
launch_docker_registry () {
echo "Launching a Docker registry for workspace snapshots."
CREATE_NEW_CONTAINER=false
# Check to see if the registry docker was not properly shut down
docker_exec inspect registry &> /dev/null || DOCKER_INSPECT_EXIT=$? || true
if [ "${DOCKER_INSPECT_EXIT}" != "1" ]; then
# Existing container running registry is found. Let's start it.
echo -e "Found a registry container named ${GREEN}registry${NC}. Attempting restart."
docker_exec start registry &>/dev/null || DOCKER_EXIT=$? || true
# Existing container found, but could not start it properly.
if [ "${DOCKER_EXIT}" == "1" ]; then
echo "Initial start of registry docker container failed... Attempting docker restart and exec."
CREATE_NEW_CONTAINER=true
fi
echo "Successful restart of registry container."
echo
# No existing Che container found, we need to create a new one.
else
CREATE_NEW_CONTAINER=true
fi
if ${CREATE_NEW_CONTAINER} ; then
# Container in bad state or not found, kill and launch new container.
kill_and_launch_docker_registry
fi
}
perform_database_migration() {
CHE_DATA=/data
if [ -f ${CHE_DATA}/db/che.mv.db ]; then
echo "!!! Detected Che database, that is stored by an old path: ${CHE_DATA}/db/che.mv.db"
echo "!!! In case if you want to use it, move it manually to the new path ${CHE_DATA}/storage/db/che.mv.db"
echo "!!! It will be moved there automatically, if no database is present by the new path"
if [ ! -f ${CHE_DATA}/storage/db/che.mv.db ]; then
mkdir -p ${CHE_DATA}/storage/db
mv ${CHE_DATA}/db/che.mv.db ${CHE_DATA}/storage/db/che.mv.db
echo "Database has been successfully moved to the new path"
fi
fi
}
init() {
### Any variables with export is a value that native Tomcat che.sh startup script requires
export CHE_IP=${CHE_IP}
if [ -f "/assembly/tomcat/bin/catalina.sh" ]; then
echo "Found custom assembly..."
export CHE_HOME="/assembly"
else
echo "Using embedded assembly..."
export CHE_HOME=$(echo /home/user/eclipse-che/)
fi
### We need to discover the host mount provided by the user for `/data`
export CHE_DATA="/data"
CHE_DATA_HOST=$(get_che_data_from_host)
CHE_USER=${CHE_USER:-root}
export CHE_USER=$CHE_USER
if [ "$CHE_USER" != "root" ]; then
if [ ! $(getent group docker) ]; then
echo "!!!"
echo "!!! Error: The docker group doesn't exist."
echo "!!!"
exit 1
fi
export CHE_USER_ID=${CHE_USER}
sudo chown -R ${CHE_USER} ${CHE_DATA}
sudo chown -R ${CHE_USER} ${CHE_HOME}
sudo chown -R ${CHE_USER} ${CHE_LOGS_DIR}
fi
[ -z "$CHE_DATABASE" ] && export CHE_DATABASE=${CHE_DATA}/storage
[ -z "$CHE_TEMPLATE_STORAGE" ] && export CHE_TEMPLATE_STORAGE=${CHE_DATA}/templates
perform_database_migration
# CHE_DOCKER_IP_EXTERNAL must be set if you are in a VM.
HOSTNAME=${CHE_DOCKER_IP_EXTERNAL:-$(get_docker_external_hostname)}
if has_external_hostname; then
# Internal property used by Che to set hostname.
export CHE_DOCKER_IP_EXTERNAL=${HOSTNAME}
fi
### Necessary to allow the container to write projects to the folder
[ -z "$CHE_WORKSPACE_STORAGE__MASTER__PATH" ] && export CHE_WORKSPACE_STORAGE__MASTER__PATH=${CHE_DATA}/workspaces
[ -z "$CHE_WORKSPACE_STORAGE" ] && export CHE_WORKSPACE_STORAGE="${CHE_DATA_HOST}/workspaces"
[ -z "$CHE_WORKSPACE_STORAGE_CREATE_FOLDERS" ] && export CHE_WORKSPACE_STORAGE_CREATE_FOLDERS=false
# Cleanup no longer in use stacks folder, accordance to a new loading policy.
if [[ -d "${CHE_DATA}"/stacks ]];then
rm -rf "${CHE_DATA}"/stacks
fi
# replace samples.json each run to make sure that we are using corrent samples from the assembly.
# also it allows users to store their own samples which should not be touched by us.
mkdir -p "${CHE_DATA}"/templates
rm -rf "${CHE_DATA}"/templates/samples.json
cp -rf "${CHE_HOME}"/templates/* "${CHE_DATA}"/templates
# A che property, which names the Docker network used for che + ws to communicate
if [ -z "$CHE_DOCKER_NETWORK" ]; then
NETWORK_NAME="bridge"
else
NETWORK_NAME=$CHE_DOCKER_NETWORK
fi
export JAVA_OPTS="${JAVA_OPTS} -Dche.docker.network=$NETWORK_NAME"
}
add_cert_to_truststore() {
if [ "${OPENSHIFT_IDENTITY_PROVIDER_CERTIFICATE}" != "" ]; then
echo "Found a custom cert. Adding it to java trust store..."
echo "${OPENSHIFT_IDENTITY_PROVIDER_CERTIFICATE}" > /home/user/openshift.crt
echo yes | keytool -keystore /home/user/openshift.jks -importcert -alias HOSTDOMAIN -file /home/user/openshift.crt -storepass minishift
export JAVA_OPTS="${JAVA_OPTS} -Djavax.net.ssl.trustStore=/home/user/openshift.jks -Djavax.net.ssl.trustStorePassword=minishift"
fi
}
get_che_data_from_host() {
DEFAULT_DATA_HOST_PATH=/data
CHE_SERVER_CONTAINER_ID=$(get_che_server_container_id)
# If `docker inspect` fails $DEFAULT_DATA_HOST_PATH is returned
echo $(docker inspect --format='{{(index .Volumes "/data")}}' $CHE_SERVER_CONTAINER_ID 2>/dev/null || echo $DEFAULT_DATA_HOST_PATH)
}
get_che_server_container_id() {
# Returning `hostname` doesn't work when running Che on OpenShift/Kubernetes/Docker Cloud.
# In these cases `hostname` correspond to the pod ID that is different from
# the container ID
echo $(basename "$(head /proc/1/cgroup || hostname)");
}
is_docker_for_mac_or_windows() {
if uname -r | grep -q 'linuxkit'; then
return 0
elif uname -r | grep -q 'moby'; then
return 0
else
return 1
fi
}
get_docker_external_hostname() {
if is_docker_for_mac_or_windows; then
echo "localhost"
else
echo ""
fi
}
has_external_hostname() {
if [ "${HOSTNAME}" = "" ]; then
return 1
else
return 0
fi
}
# SITTERM / SIGINT
responsible_shutdown() {
echo ""
echo "Received SIGTERM"
stop_che_server &
wait ${PID}
exit;
}
set -e
set +o posix
# setup handlers
# on callback, kill the last background process, which is `tail -f /dev/null` and execute the specified handler
trap 'responsible_shutdown' SIGHUP SIGTERM SIGINT
init
init_global_variables
set_environment_variables
add_cert_to_truststore
# run che
start_che_server &
PID=$!
# See: http://veithen.github.io/2014/11/16/sigterm-propagation.html
wait ${PID}
wait ${PID}
EXIT_STATUS=$?
# wait forever
while true
do
tail -f /dev/null & wait ${!}
done